簡體   English   中英

為什么這個MySQL查詢異常緩慢並且沒有使用正確的索引?

[英]Why is this MySQL query incredibly slow and not using the right index?

執行大約需要100秒:

SELECT part.*
FROM   (((((((`part` 
              LEFT JOIN `engine_x_category_1_x_category_2_x_part` 
                     ON `engine_x_category_1_x_category_2_x_part`.`part_id` = 
                      `part`.`id`) 
             LEFT JOIN `engine_x_category_1_x_category_2` 
                    ON 
`engine_x_category_1_x_category_2_x_part`.`engine_x_category_1_x_category_2_id` 
= `engine_x_category_1_x_category_2`.`id`) 
LEFT JOIN `engine_x_category_1` 
       ON `engine_x_category_1_x_category_2`.`engine_x_category_1_id` = 
          `engine_x_category_1`.`id`) 
 LEFT JOIN `engine` 
        ON `engine_x_category_1`.`engine_id` = `engine`.`id`) 
LEFT JOIN `model` 
       ON `engine`.`model_id` = `model`.`id`) 
 LEFT JOIN `year` 
        ON `model`.`year_id` = `year`.`id`) 
LEFT JOIN `make` 
       ON `year`.`make_id` = `make`.`id`) 
LEFT JOIN `category_1` 
      ON `engine_x_category_1`.`category_1_id` = `category_1`.`id` 
WHERE  1 > 0 
       AND `category_1`.`id` > 0 
GROUP  BY `part`.`id` 
ORDER  BY `part`.`id` ASC 
LIMIT  0, 20 

但是,一旦我們擺脫AND category_1.id > 0 ,它只需要0.003秒。

這真的很奇怪,因為category_1.id是PRIMARY KEY列,而表category_1只有26行。

category_1結構和鍵

在此處輸入圖片說明

查詢說明:

該查詢的MySQL EXPLAIN

這有什么問題嗎? 為什么MySQL不為category_1.id使用PRIMARY索引,而是為時間戳列使用索引ts

PS MySQL版本:5.6.33

更新1

正如O. Jones指出的那樣,我嘗試使用表category_1 FORCE INDEX (PRIMARY) ,並且EXPLAIN顯示查詢正確使用了PRIMARY而不是ts作為category_1.id的索引,但是查詢仍然需要近100秒鍾來執行。

似乎category_1.id不是這里的罪魁禍首。

更新2

在@ O.Jones的建議之后,我擺脫了與makeyearmodelengine無關的JOIN:

SELECT part.*
FROM   (((`part` 
              LEFT JOIN `engine_x_category_1_x_category_2_x_part` 
                     ON `engine_x_category_1_x_category_2_x_part`.`part_id` = 
                      `part`.`id`) 
             LEFT JOIN `engine_x_category_1_x_category_2` 
                    ON 
`engine_x_category_1_x_category_2_x_part`.`engine_x_category_1_x_category_2_id` 
= `engine_x_category_1_x_category_2`.`id`) 
LEFT JOIN `engine_x_category_1` 
       ON `engine_x_category_1_x_category_2`.`engine_x_category_1_id` = 
          `engine_x_category_1`.`id`) 
LEFT JOIN `category_1` 
      ON `engine_x_category_1`.`category_1_id` = `category_1`.`id` 
WHERE  1 > 0 
       AND `category_1`.`id` > 0 
GROUP  BY `part`.`id` 
ORDER  BY `part`.`id` ASC 
LIMIT  0, 20

說明

現在查詢僅花費大約0.003秒。

雖然這可以回答此特定查詢的問題,但它顯然不是最終的解決方案,因為人們可能還需要同時通過category_1make來搜索汽車零件,因此無法刪除查詢中的任何JOIN:

SELECT part.*
FROM   (((((((`part` 
              LEFT JOIN `engine_x_category_1_x_category_2_x_part` 
                     ON `engine_x_category_1_x_category_2_x_part`.`part_id` = 
                      `part`.`id`) 
             LEFT JOIN `engine_x_category_1_x_category_2` 
                    ON 
`engine_x_category_1_x_category_2_x_part`.`engine_x_category_1_x_category_2_id` 
= `engine_x_category_1_x_category_2`.`id`) 
LEFT JOIN `engine_x_category_1` 
       ON `engine_x_category_1_x_category_2`.`engine_x_category_1_id` = 
          `engine_x_category_1`.`id`) 
 LEFT JOIN `engine` 
        ON `engine_x_category_1`.`engine_id` = `engine`.`id`) 
LEFT JOIN `model` 
       ON `engine`.`model_id` = `model`.`id`) 
 LEFT JOIN `year` 
        ON `model`.`year_id` = `year`.`id`) 
LEFT JOIN `make` 
       ON `year`.`make_id` = `make`.`id`) 
LEFT JOIN `category_1` 
      ON `engine_x_category_1`.`category_1_id` = `category_1`.`id` 
WHERE  1 > 0 
       AND `category_1`.`id` > 0
       AND `make`.`id` > 0
GROUP  BY `part`.`id` 
ORDER  BY `part`.`id` ASC 
LIMIT  0, 20

說明

經過幾次測試,它仍然可以運行約80-100秒。

我們現在該做什么?

更新3

遵循@LuisMuñoz的建議,我將條件從WHERE移到了相應的JOIN ON子句:

SELECT part.*
FROM   (((((((`part` 
              LEFT JOIN `engine_x_category_1_x_category_2_x_part` 
                     ON `engine_x_category_1_x_category_2_x_part`.`part_id` = 
                      `part`.`id`) 
             LEFT JOIN `engine_x_category_1_x_category_2` 
                    ON 
`engine_x_category_1_x_category_2_x_part`.`engine_x_category_1_x_category_2_id` 
= `engine_x_category_1_x_category_2`.`id`) 
LEFT JOIN `engine_x_category_1` 
       ON `engine_x_category_1_x_category_2`.`engine_x_category_1_id` = 
          `engine_x_category_1`.`id`) 
 LEFT JOIN `engine` 
        ON `engine_x_category_1`.`engine_id` = `engine`.`id`) 
LEFT JOIN `model` 
       ON `engine`.`model_id` = `model`.`id`) 
 LEFT JOIN `year` 
        ON `model`.`year_id` = `year`.`id`) 
JOIN `make` 
  ON `year`.`make_id` = `make`.`id` 
     AND `make`.`id` > 0) 
JOIN `category_1` 
 ON `engine_x_category_1`.`category_1_id` = `category_1`.`id` 
    AND `category_1`.`id` > 0 
WHERE  1 > 0 
GROUP  BY `part`.`id` 
LIMIT  0, 10 

說明

必須使用JOIN代替LEFT JOIN,否則條件將不生效。

但是,它仍然像條件在WHERE子句中一樣慢。

很少有建議嘗試加快查詢速度(我查看了最近的更新#3):

  • 確保查詢不會返回太多行(當X是您定義的合理數字時,用戶看不到多於X行)。 最好通過添加過濾條件(已建立索引)來過濾行,但是您也可以添加LIMIT子句。
  • 添加索引以加快搜索速度(此查詢的建議索引如下)。
  • 您正在使用LEFT聯接到category_1,但是正在過濾該表的ID( category_1.id > 0 )。 因此,您可以改為將單詞LEFT to INNER JOIN刪除到該表中,這可以加快查詢速度。

添加以下索引:

ALTER TABLE `category_1` ADD INDEX `category_1_idx_id` (`id`);
ALTER TABLE `engine_x_category_1` ADD INDEX `engine_x_category_1_idx_id` (`category_1_id`);
ALTER TABLE `make` ADD INDEX `make_idx_id` (`id`);
ALTER TABLE `part` ADD INDEX `part_idx_id` (`id`);

暫無
暫無

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

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