我們有一個相對直接的查詢,可以在4個表中進行LEFT JOIN。 A是層級中的「主」表或最頂層的表。乙鏈接A,C鏈接B.此外,X鏈接答:這樣的層次結構基本上是MySQL查詢優化;選擇多個字段與JOIN
A
C => B => A
X => A
查詢基本上是:
SELECT
a.*, b.*, c.*, x.*
FROM
a
LEFT JOIN b ON b.a_id = a.id
LEFT JOIN c ON c.b_id = b.id
LEFT JOIN x ON x.a_id = a.id
WHERE
b.flag = true
ORDER BY
x.date DESC
LIMIT 25
通過EXPLAIN
,我已經證實, 有正確的索引,並且內置的MySQL查詢優化器正確使用這些索引並正確使用。
因此,這裏的怪一部分...
當我們作爲查詢運行,它需要大約1.1秒的運行。
但是,在做了一些檢查之後,似乎如果我刪除了大部分SELECT字段,我會得到一個明顯提高的顯着的。
所以,如果不是我們製作成兩步查詢過程如下:
- 第一個查詢相同,所不同的SELECT子句更改爲只
SELECT a.id
,而不是SELECT *
- 第二個查詢也和上面一樣,除了將WHERE子句改爲只執行
a.id IN
查詢1的結果而不是之前的結果
結果是截然不同的。第一個查詢爲.03秒,第二個查詢爲.02。
在代碼中執行這兩步查詢本質上爲我們提供了20倍的性能提升。
因此,這裏是我的問題:
不應該在該類型的優化已經在數據庫引擎內進行?爲什麼實際選擇哪個字段的差異會影響查詢的整體性能?
在一天結束時,它只是選擇完全相同的25行並返回完全相同的25行內容。那麼,爲什麼表現差距很大呢?
ADDED 2012-08-24 13:02 PM PDT
感謝eggyal和invertedSpear的反饋。首先,這不是一個緩存問題 - 我已經運行了兩次測試,每次在兩種方法之間交替進行兩次查詢(大約10次)。第一種(單個查詢)方法的結果平均值爲1.1秒,第二種(2查詢)方法的平均值爲.03 + 0.02秒。
就索引而言,我認爲我已經做了一個EXPLAIN以確保我們通過關鍵點,而且我們大部分都是。不過,我只是再次做了一個快速檢查,一個有趣的事情需要注意:
較慢的「單個查詢」的做法不顯示額外注「使用索引」爲三線:
+----+-------------+-------+--------+------------------------+-------------------+---------+-------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+------------------------+-------------------+---------+-------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | t1 | index | PRIMARY | shop_group_id_idx | 5 | NULL | 102 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | t2 | eq_ref | PRIMARY | PRIMARY | 4 | dbmodl_v18.t1.organization_id | 1 | Using where |
| 1 | SIMPLE | t0 | ref | bundle_idx,shop_id_idx | shop_id_idx | 4 | dbmodl_v18.t1.organization_id | 309 | |
| 1 | SIMPLE | t3 | eq_ref | PRIMARY | PRIMARY | 4 | dbmodl_v18.t0.id | 1 | |
+----+-------------+-------+--------+------------------------+-------------------+---------+-------------------------------+------+----------------------------------------------+
雖然確實秀「使用索引」因爲當我們只是的ID查詢:
+----+-------------+-------+--------+------------------------+-------------------+---------+-------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+------------------------+-------------------+---------+-------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | t1 | index | PRIMARY | shop_group_id_idx | 5 | NULL | 102 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | t2 | eq_ref | PRIMARY | PRIMARY | 4 | dbmodl_v18.t1.organization_id | 1 | Using where |
| 1 | SIMPLE | t0 | ref | bundle_idx,shop_id_idx | shop_id_idx | 4 | dbmodl_v18.t1.organization_id | 309 | Using index |
| 1 | SIMPLE | t3 | eq_ref | PRIMARY | PRIMARY | 4 | dbmodl_v18.t0.id | 1 | |
+----+-------------+-------+--------+------------------------+-------------------+---------+-------------------------------+------+----------------------------------------------+
奇怪的是,無論做列出正確的索引使用...但我猜它迴避了問題:
他們爲什麼不同(考慮所有其他條款是完全相同的)?這是一個爲什麼它更慢的跡象?
不幸的是,在EXPLAIN
結果中,當「Extra」列爲空/ null時,MySQL文檔沒有提供太多的信息。
如果可以從索引中提取列而不查找實際記錄('EXPLAIN'顯示'Using index'),那麼您可能會看到顯着的性能提升。這是怎麼回事? – eggyal
它真的更快嗎?還是剛纔表格緩存在內存中?測試之間的「刷新表」和「重置查詢緩存」將爲您提供更真實的基準測試。 – invertedSpear