由于subselect导致mysql数量减慢

时间:2011-01-12 09:19:24

标签: mysql indexing subquery

如何让这个select语句更快? 使用subselect的第一个左连接使它变慢...

mysql>   SELECT COUNT(DISTINCT w1.id) AS AMOUNT FROM tblWerbemittel w1
    JOIN tblVorgang v1 ON w1.object_group = v1.werbemittel_id
    INNER JOIN ( SELECT wmax.object_group, MAX( wmax.object_revision ) wmaxobjrev FROM tblWerbemittel wmax GROUP BY wmax.object_group ) AS wmaxselect ON w1.object_group = wmaxselect.object_group AND w1.object_revision = wmaxselect.wmaxobjrev
    LEFT JOIN ( SELECT vmax.object_group, MAX( vmax.object_revision ) vmaxobjrev FROM tblVorgang vmax GROUP BY vmax.object_group ) AS vmaxselect ON v1.object_group = vmaxselect.object_group AND v1.object_revision = vmaxselect.vmaxobjrev
    LEFT JOIN tblWerbemittel_has_tblAngebot wha ON wha.werbemittel_id = w1.object_group
    LEFT JOIN tblAngebot ta ON ta.id = wha.angebot_id
    LEFT JOIN tblLieferanten tl ON tl.id = ta.lieferant_id AND wha.zuschlag = (SELECT MAX(zuschlag) FROM tblWerbemittel_has_tblAngebot WHERE werbemittel_id = w1.object_group)
    WHERE w1.flags =0 AND v1.flags=0;

        +--------+
        | AMOUNT |
        +--------+
        |   1982 |
        +--------+
        1 row in set (1.30 sec)

已经设置了一些索引,并且EXPLAIN显示它们已被使用。

+----+--------------------+-------------------------------+--------+----------------------------------------+----------------------+---------+-----------------------------------------------+------+----------------------------------------------+
| id | select_type        | table                         | type   | possible_keys                          | key                  | key_len | ref                                           | rows | Extra                                        |
+----+--------------------+-------------------------------+--------+----------------------------------------+----------------------+---------+-----------------------------------------------+------+----------------------------------------------+
|  1 | PRIMARY            | <derived2>                    | ALL    | NULL                                   | NULL                 | NULL    | NULL                                          | 2072 |                                              |
|  1 | PRIMARY            | v1                            | ref    | werbemittel_group,werbemittel_id_index | werbemittel_group    | 4       | wmaxselect.object_group                       |    2 | Using where                                  |
|  1 | PRIMARY            | <derived3>                    | ALL    | NULL                                   | NULL                 | NULL    | NULL                                          | 3376 |                                              |
|  1 | PRIMARY            | w1                            | eq_ref | object_revision,or_og_index            | object_revision      | 8       | wmaxselect.wmaxobjrev,wmaxselect.object_group |    1 | Using where                                  |
|  1 | PRIMARY            | wha                           | ref    | PRIMARY,werbemittel_id_index           | werbemittel_id_index | 4       | dpd.w1.object_group                           |    1 |                                              |
|  1 | PRIMARY            | ta                            | eq_ref | PRIMARY                                | PRIMARY              | 4       | dpd.wha.angebot_id                            |    1 |                                              |
|  1 | PRIMARY            | tl                            | eq_ref | PRIMARY                                | PRIMARY              | 4       | dpd.ta.lieferant_id                           |    1 | Using index                                  |
|  4 | DEPENDENT SUBQUERY | tblWerbemittel_has_tblAngebot | ref    | PRIMARY,werbemittel_id_index           | werbemittel_id_index | 4       | dpd.w1.object_group                           |    1 |                                              |
|  3 | DERIVED            | vmax                          | index  | NULL                                   | object_revision_uq   | 8       | NULL                                          | 4668 | Using index; Using temporary; Using filesort |
|  2 | DERIVED            | wmax                          | range  | NULL                                   | or_og_index          | 4       | NULL                                          | 2168 | Using index for group-by                     |
+----+--------------------+-------------------------------+--------+----------------------------------------+----------------------+---------+-----------------------------------------------+------+----------------------------------------------+
10 rows in set (0.01 sec)

上述语句大约2秒时的主要问题似乎是没有索引可以使用的子选择。 如何更快地写出声明?

感谢您的帮助。 MT

2 个答案:

答案 0 :(得分:0)

虽然我认为我没有足够的数据来提供100%正确答案,但我可以提供一些提示。

最糟糕的是,MYSQL很愚蠢。请记住并始终重新排列查询,以便在开始时排除大多数数据。例如,如果最后一次连接将结果数量从10k减少到2k而其他连接没有,请尝试交换它们的位置,以便每个后续连接都可以在最小的数据子集上运行。

同样适用于WHERE子句。

此外,连接往往比子查询慢。我不知道这是一个规则还是我在我的案例中观察到的东西,但你总是可以尝试用子查询替换一个或两个连接。

虽然我认为这并没有真正回答你的问题,但我希望它至少可以让你知道从哪里开始寻找优化。

答案 1 :(得分:0)

您有以下索引吗?

for tblWerbemittel - object_group, object_revision
for tblVorgang - object_group, object_revision
for tblWerbemittel_has_tblAngebot - werbemittel_id, zuschlag

如果有帮助,请告诉我,还有一些我可以看到的可能有帮助,但首先尝试这些。

修改

您可以尝试这两个查询,看看它们是否运行得很快?

SELECT  w1.id AS AMOUNT 
FROM    tblWerbemittel w1 INNER JOIN 
        (SELECT     wmax.object_group, 
                    MAX( wmax.object_revision ) AS wmaxobjrev 
        FROM        tblWerbemittel AS wmax 
        GROUP BY wmax.object_group ) AS wmaxselect ON   w1.object_group = wmaxselect.object_group AND 
                                                        w1.object_revision = wmaxselect.wmaxobjrev      
WHERE   w1.flags = 0 

SELECT  v1.werbemittel_id 
FROM    tblVorgang v1 LEFT JOIN
        (SELECT     vmax.object_group, 
                    MAX( vmax.object_revision ) AS vmaxobjrev 
        FROM        tblVorgang AS vmax 
        GROUP BY    vmax.object_group ) AS  vmaxselect ON v1.object_group = vmaxselect.object_group AND 
                                            v1.object_revision = vmaxselect.vmaxobjrev LEFT JOIN 
WHERE   v1.flags = 0