2017-10-06 15 views
0

這裏,因爲它是敏感信息,我要添加查詢的一部分,我會用不實的名字:MySQL的忽略指數即使使用索引或力指數

SELECT 
    `entity`.`id`, 
    `entity`.`requirements`, 
    `entity`.`description`, 
    `entity`.`status`, 
    `entity_videos`.`length`, 
    `entity_videos`.`quality`, 
    `states`.`name`, 
    `uploads`.`id`, 
    `uploads`.`name` 
    FROM `entity` 
    LEFT JOIN `states` ON `states`.`id` = `entity`.`state_id` 
    INNER JOIN `uploads` FORCE INDEX (`uploadable_id_index`) 
     ON `uploads`.`uploadable_type` = 'Entity' 
     AND `uploads`.`category` = 'Icon' 
     AND (`uploads`.`uploadable_id` = `entity`.`id` 
       OR `uploads`.`uploadable_id` = `entity`.`parent_entity_for_icon` 
      ) 
    INNER JOIN `entity_videos` FORCE INDEX (entity_videos_entity_id_index) 
     ON `entity_videos`.`entity_id` = `entity`.`id` 
    WHERE `entity`.`status` = 'active' 

的問題是,MySQL優化不想使用uploadable_id_index索引。解釋的部分:

part of explain querye

據我所知FORCE INDEX是力優化器使用索引除外優化程序無法使用索引的情況。我應該怎麼做才能強制該索引,而不是對錶格進行全面掃描? 我試圖刪除entity_videos_entity_id_index也試圖將uploads表信息添加到where子句,但沒有爲我工作。有任何想法嗎?非常感謝您的任何幫助

更新時間:

隨着@Barmar和@PaulSpiegel的幫助下,我發現,問題是(uploads.uploadable_id = entity.id OR uploads.uploadable_id = entity.parent_entity_for_icon)。並與查詢了一段時間,我發現我的情況是最好的解決辦法是打:

SELECT 
    `entity`.`id`, 
    `entity`.`requirements`, 
    `entity`.`description`, 
    `entity`.`status`, 
    `entity_videos`.`length`, 
    `entity_videos`.`quality`, 
    `states`.`name`, 
    `icon`.`id`, 
    `icon`.`name`, 
    `parent_offer_icon`.`id`, 
    `parent_offer_icon`.`name` 
    FROM `entity` 
    LEFT JOIN `states` ON `states`.`id` = `entity`.`state_id` 
    LEFT JOIN `uploads` as `icon` FORCE INDEX (`uploadable_id_index`) 
     ON `icon`.`uploadable_type` = 'Entity' 
     AND `icon`.`category` = 'Icon' 
     AND `icon`.`uploadable_id` = `entity`.`id` 
    LEFT JOIN `uploads` as `parent_offer_icon` FORCE INDEX (`uploadable_id_index`) 
     ON `parent_offer_icon`.`uploadable_type` = 'Entity' 
     AND `parent_offer_icon`.`category` = 'Icon' 
     AND `parent_offer_icon`.`uploadable_id` = `entity`.`parent_entity_for_icon` 
    INNER JOIN `entity_videos` FORCE INDEX (entity_videos_entity_id_index) 
     ON `entity_videos`.`entity_id` = `entity`.`id` 
    WHERE `entity`.`status` = 'active' 
     AND (parent_offer_icon.id IS NOT NULL 
       OR icon.id IS NOT NULL) 

我仍然開放給其他建議:)

+1

「OR」條件可能是問題所在。嘗試使用'uploadable_id IN(entity.id,entity.parent_entity_for_icon)' – Barmar

+0

@Barmar謝謝你的建議,但它也不起作用。我忘記了,前幾天數據庫優化器中的記錄數量少得多的時候,選擇該索引,現在真的可以更快地完成全面掃描而不是使用索引了嗎? –

+0

當表變大時,通常索引更有用。但也許該指數的基數太低。使用'SHOW INDEX FROM uploads;'來查看。 – Barmar

回答

1

讓我們通過轉動討厭ORUNION開始:

(SELECT e.id AS eid, 
      u.id AS uid, 
      u.name AS uname 
    FROM `uploads` AS u 
    INNER JOIN `entity` AS e 
     ON u.`uploadable_id` = e.`id` 
    WHERE u.`uploadable_type` = 'Entity' 
     AND u.`category` = 'Icon' 
     AND e.status = 'active' 
) UNION DISTINCT 
(SELECT e.id AS eid, 
      u.id AS uid, 
      u.name AS uname 
    FROM `uploads` AS u 
    INNER JOIN `entity` AS e 
     ON u.`uploadable_id` = e.`parent_entity_for_icon` 
    WHERE u.`uploadable_type` = 'Entity' 
     AND u.`category` = 'Icon' 
     AND e.status = 'active' 
) 

這將需要一些指標:

uploads: INDEX(uploadable_type, category, uploadable_id, id, name) 
entity: INDEX(parent_entity_for_icon, status, id) 

(我假設entityPRIMARY KEY(id)?請提供SHOW CREATE TABLE,這樣我就不必猜測了。)如果這樣長的索引存在問題,請告訴我;我可以提供一種解決方法。

通過將OR轉換爲UNION,可以爲每個零件使用不同的索引。通過OR,優化器通常會踢出並且效率低下。

請驗證上面的查詢運行速度快,併產生合理的輸出。然後......

SELECT e.`id`, e.`requirements`, e.`description`, e.`status`, 
     ev.`length`, ev.`quality`, 
     s.`name`, 
     uid, uname 
    FROM (the-query-above) AS i 
    JOIN `entity` AS e ON e.id = i.eid 
    LEFT JOIN `states` AS s ON s.`id` = e.`state_id` 
    INNER JOIN `entity_videos` AS ev ON ev.`entity_id` = i.eid 

除了PRIMARY KEY(id)在每張桌子上,你將需要

entity_videos: INDEX(entity_id) -- good, or 
entity_videos: INDEX(entity_id, length, quality) -- better ("covering") 

不要使用FORCE INDEX

更多關於創建索引:http://mysql.rjweb.org/doc.php/index_cookbook_mysql

+0

感謝您的建議,我相信這可能是最好的建議,但就我而言,使用您的解決方案和我的解決方案執行查詢需要相當多的時間,但您的解決方案很難使用ORM實現。我看到你的個人資料,看起來你是MySQL的專家:)。也許你會有興趣看到完整的查詢和表格結構,我們可以繼續談話(也許通過電子郵件或其他方式)?無論如何,謝謝你! –

+0

是的,ORM傾向於妨礙表現。 mysql在rjweb點org。你可以通過計算'UNION'和相應的'OR'開始計算指數。 –

相關問題