簡體   English   中英

使用內部聯接優化MySQL查詢

[英]Optimizing MySQL query with 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 |
+----+-------------+------------+--------+---------------+-----------+---------+------------------------------+-------+------------------------------+

除非我誤解了您提供的信息,否則我相信您可以重新編寫上述查詢,如下所示

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

使用這些值,您可以准確地看到引擎蓋下發生了什么。

遺憾的是,如果不知道表中的數據,引擎類型和查詢中使用的數據類型,很難就如何優化提出建議。

我已使用連接而不是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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM