簡體   English   中英

優化3個表之間的MySQL Left Join查詢以減少執行時間

[英]Optimizing MySQL Left join query between 3 tables to reduce execution time

我有以下查詢:

SELECT region.id, region.world_id, min_x, min_y, min_z, max_x, max_y, max_z, version, mint_version 
FROM minecraft_worldguard.region 
LEFT JOIN minecraft_worldguard.region_cuboid 
ON region.id = region_cuboid.region_id 
AND region.world_id = region_cuboid.world_id 
LEFT JOIN minecraft_srvr.lot_version 
ON id=lot 
WHERE region.world_id = 10 
AND region_cuboid.world_id=10;

Mysql慢速查詢日志告訴我,執行需要5秒鍾以上的時間,返回2300行,但檢查15'404'545行以返回它。

這三個表各有6500行,只有id和lot字段上的唯一鍵以及world_id字段上的鍵。 我試圖通過根據長方體和世界的ID以及world_id上的雙WHERE來過濾長方體和世界,以盡量減少檢查的行數,但這似乎無濟於事。

知道如何優化此查詢嗎?

這是帶有當前狀態索引的sqlfiddle

在這種情況下,MySQL無法使用索引,因為連接的字段具有不同的數據類型:

  `lot` varchar(20) COLLATE utf8_unicode_ci NOT NULL
  `id` varchar(128) COLLATE utf8_bin NOT NULL

如果將此字段的類型更改為常規類型(例如,將region.idutf8_unicode_ci ),則MySQL使用主鍵( fiddle )。

根據文檔

如果無法在不進行轉換的情況下直接比較值,則比較不同的列(例如,將字符串列與時間或數字列進行比較)可能會阻止使用索引。

您已將兩個表“ minecraft_worldguard.region”和“ minecraft_worldguard.region_cuboid”加入到region.world_id和region_cuboid.world_id上。 因此,WHERE子句不需要兩個條件。

WHERE子句中的兩列已等於JOIN條件,因此您無需檢查WHERE子句中的兩個條件。 在WHERE子句中刪除其中之一,並在保留WHERE條件的列上添加索引。

在您的示例中,保留WHERE子句如下:WHERE region.world_id = 10

並在region.world_id列上添加索引,這將提高性能。

注意:請注意,我建議您丟棄“ AND region_cuboid.world_id = 10;”。 WHERE子句的一部分。

希望能有所幫助。

首先,編寫具有多個表的查詢時,習慣於“別名”對表的引用是一件非常好的事情,這樣您就不必在整個過程中都重新輸入整個長名。 同樣,確定列來自哪些表是一個非常好的主意,以使用戶更好地了解哪些地方可以幫助提高性能(例如建議覆蓋索引)。

就是說,我已經對您的原始查詢應用了別名,但是會按相應列對表進行猜測,但是顯然您可以快速識別並進行調整。

SELECT 
      R.id, 
      R.world_id, 
      RC.min_x, 
      RC.min_y, 
      RC.min_z, 
      RC.max_x, 
      RC.max_y, 
      RC.max_z, 
      LV.version, 
      LV.mint_version 
   FROM 
      minecraft_worldguard.region R
         LEFT JOIN minecraft_worldguard.region_cuboid RC
            ON R.id = RC.region_id 
            AND R.world_id = RC.world_id 
         LEFT JOIN minecraft_srvr.lot_version LV
            ON R.id = LV.lot 
   WHERE 
      R.world_id = 10 

我還從where子句中刪除了您的“ region_cuboid.world_id = 10”,這是由於基於區域AND world的JOIN子句的結果是多余的。

為了建議索引,並且如果我對列有適當的別名引用,我建議在(world_id,id)的區域表上建議覆蓋索引。 第一個位置的“ World_id”很快使WHERE子句合格,並且RC和LV表的“ id”在那里。

對於region_cuboid表,我還要在(world_id,region_id)上有一個索引,以匹配要加入該表的區域表。

對於lot_version表,在(批次)上具有索引,或在(批次,版本,mint_version)上具有覆蓋索引

暫無
暫無

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

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