使用内部联接优化MySQL查询

时间:2011-11-02 04:50:41

标签: mysql sql query-optimization inner-join

我花了很多时间来优化这个查询,但它开始因较大的表而变慢。我想这些可能是最糟糕的问题类型,但我正在寻找一些指导。我并不是真的可以自由地披露数据库架构,所以希望这是足够的信息。谢谢,

SELECT tblA.id, tblB.id, tblC.id, tblD.id
FROM tblA, tblB, tblC, tblD
INNER JOIN (SELECT max(tblB.id) AS xid
                FROM tblB
                WHERE tblB.rdd = 11305
                GROUP BY tblB.index_id
                ORDER BY NULL) AS rddx
           ON tblB.id = rddx.xid
WHERE
    tblA.id = tblB.index_id
    AND tblC.name = tblD.s_type
    AND tblD.name = tblA.s_name
GROUP BY tblA.s_name
ORDER BY NULL;

之间存在一对多的关系
  • tblA.id和tblB.index_id
  • tblC.name和tblD.s_type
  • tblD.name和tblA.s_name
+----+-------------+------------+--------+---------------+-----------+---------+------------------------------+-------+------------------------------+
| id | select_type | table      | type   | possible_keys | key       | key_len | ref                          | rows  | Extra                        |
+----+-------------+------------+--------+---------------+-----------+---------+------------------------------+-------+------------------------------+
|  1 | PRIMARY     | derived2   | ALL    | NULL          | NULL      | NULL    | NULL                         | 32568 | Using temporary              |
|  1 | PRIMARY     | tblB       | eq_ref | PRIMARY       | PRIMARY   | 8       | rddx.xid                     |     1 |                              |
|  1 | PRIMARY     | tblA       | eq_ref | PRIMARY       | PRIMARY   | 8       | tblB.index_id                |     1 | Using where                  |
|  1 | PRIMARY     | tblD       | eq_ref | PRIMARY       | PRIMARY   | 22      | tblA.s_name                  |     1 | Using where                  |
|  1 | PRIMARY     | tblC       | eq_ref | PRIMARY       | PRIMARY   | 22      | tblD.s_type                  |     1 |                              |
|  2 | DERIVED     | tblB       | ref    | rdd_idx       | rdd_idx   | 7       |                              | 65722 | Using where; Using temporary |
+----+-------------+------------+--------+---------------+-----------+---------+------------------------------+-------+------------------------------+

2 个答案:

答案 0 :(得分:2)

除非我误解了您提供的信息,否则我相信您可以重新编写上述查询,如下所示

EXPLAIN SELECT tblA.id, MAX(tblB.id), tblC.id, tblD.id
FROM tblA
LEFT JOIN tblD ON tblD.name = tblA.s_name
LEFT JOIN tblC ON tblC.name = tblD.s_type
LEFT JOIN tblB ON tblA.id = tblB.index_id
WHERE tblB.rdd = 11305
ORDER BY NULL;

显然我无法为此提供解释,因为解释取决于数据库中的数据。看到关于这个查询的解释会很有趣。

显然,解释只能估计会发生什么。您可以使用SHOW SESSION STATUS来详细说明运行实际查询时发生的情况。确保在运行您正在调查的查询之前运行,以便您可以读取干净的数据。所以在这种情况下你会运行

FLUSH STATUS;

EXPLAIN SELECT tblA.id, MAX(tblB.id), tblC.id, tblD.id
FROM tblA
LEFT JOIN tblD ON tblD.name = tblA.s_name
LEFT JOIN tblC ON tblC.name = tblD.s_type
LEFT JOIN tblB ON tblA.id = tblB.index_id
WHERE tblB.rdd = 11305
ORDER BY NULL;

SHOW SESSION STATUS LIKE 'ha%';

这为您提供了许多指标,用于显示执行查询时实际发生的情况。

Handler_read_rnd_next - Number of requests to read next row in the data file
Handler_read_key - Number of requests to read a row based on a key
Handler_read_next - Number of requests to read the next row in key order

使用这些值,您可以准确了解幕后发生的事情。

不幸的是,如果不知道表中的数据,引擎类型和查询中使用的数据类型,很难就如何优化提出建议。

答案 1 :(得分:1)

我已使用连接而不是WHERE子句中的连接更新了查询。另外,通过查看它,作为开发人员,您可以直接查看表之间的关系。 A-> B,A-> D和D-> C.现在,在表B中,您希望基于公共“ID = Index_ID”的最高ID,并且RDD = 11305将不需要完整的子查询。但是,这已将“MAX()”移动到字段选择子句的上部。我会确保你有一个关于tblB的索引(index_id,rdd)。最后,通过执行STRAIGHT_JOIN将有助于根据具体列出的方式强制执行查询运行。

- 来自评论的编辑 -

看来你从tblB得到了空值。这通常表示有效的tblA记录,但没有相同ID的RDB = 11305的tblB记录。也就是说,看起来你只关心那些与11305相关的条目,所以我相应地调整了查询​​。请确保您在tblB上有一个基于“RDD”列的索引(至少在多列索引的情况下位于第一个位置)

正如您在本文中所看到的,我仅从表B中查询11305个条目并通过index_ID进行预分组(与tblA链接)。这给了我一个记录,每个索引它们将存在...从这个结果,我加入回A,然后再次直接回到B,但是根据找到的最高匹配ID,然后D和C一如既往。所以现在,您可以从任何表中获取任何列并获得正确的记录...此查询中应该没有剩余的NULL值。

希望我已经澄清了我是如何为你准备的。

SELECT STRAIGHT_JOIN 
      PreQuery.HighestPerIndexID
      tblA.id, 
      tblA.AnotherAField,
      tblA.Etc,
      tblB.SomeOtherField,
      tblB.AnotherField,
      tblC.id, 
      tblD.id
   FROM 
      ( select PQ1.Index_ID,
               max( PQ1.ID ) as HighestPerIndexID
           from tblB PQ1
           where PQ1.RDD = 11305
           group by PQ1.Index_ID ) PreQuery

         JOIN tblA
            on PreQuery.Index_ID = tblA.ID

         join tblB
            on PreQuery.HighestPerIndexID = tblB.ID

         join tblD
            on tblA.s_Name = tblD.name

            join tblC
               on tblD.s_type = tblC.Name
    ORDER BY 
       tblA.s_Name