簡體   English   中英

適當的索引/優化MySQL GROUP BY和JOIN查詢

[英]Proper Indexing/Optimization of a MySQL GROUP BY and JOIN Query

我已經做了很多閱讀和谷歌搜索,我找不到任何滿意的答案,所以我很感激任何幫助。 我找到的大多數答案都接近我的情況,但沒有解決它(並試圖遵循解決方案並沒有給我任何好處)。

請參閱下面的編輯#2以獲得最佳示例


[這是最初的問題,但不能代表我的要求。]

假設我有2個表,每個表有4列:

  • key(int,auto increment)
  • c1(約會)
  • c2(長度為3的varchar)
  • c3(也是長度為3的varchar)

我想執行以下查詢:

SELECT t.c1, t.c2, COUNT(*)
FROM test1 t
LEFT JOIN test2 t2 ON t2.key = t.key
GROUP BY t.c1, t.c2

兩個key段都被索引為主鍵。 我想獲得每個c1,c2組中返回的行數。

當我解釋這個查詢時,我得到“使用臨時;使用filesort”。 我正在執行此查詢的實際表超過500,000行,這意味着它是一個耗時的查詢。

所以我的問題是(假設我在查詢中沒有做任何錯誤):有沒有辦法索引這個表來消除臨時/ filesort用法?

在此先感謝您的幫助。

編輯

這是表定義(在這個例子中,兩個表都是相同的 - 實際上它們不是,但我不確定它在這一點上有所不同):

CREATE TABLE `test1` (
 `key` int(11) NOT NULL auto_increment,
 `c1` date NOT NULL,
 `c2` varchar(3) NOT NULL,
 `c3` varchar(3) NOT NULL,
 PRIMARY KEY  (`key`),
 UNIQUE KEY `c1` (`c1`,`c2`),
 UNIQUE KEY `c2_2` (`c2`,`c1`),
 KEY `c2` (`c2`,`c3`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8

完整的EXPLAIN聲明:

id   select_type  table  type    possible_keys  key      key_len  ref             rows   Extra
1    SIMPLE       t      ALL     NULL           NULL     NULL     NULL            2      Using temporary; Using filesort
1    SIMPLE       t2     eq_ref  PRIMARY        PRIMARY  4        tracking.t.key  1      Using index

這僅適用於我的示例表。 在我的真實表中,t的行表示500,000+(表中的每一行,盡管這可能與其他內容有關)。


編輯#2

這是一個更具體的例子來更好地解釋我的情況。

假設我有小聯盟棒球比賽的數據。 我有兩張桌子。 一個人掌握游戲數據:

CREATE TABLE `ex_games` (
 `game_id` int(11) NOT NULL auto_increment,
 `home_team` int(11) NOT NULL,
 `date` date NOT NULL,
 PRIMARY KEY  (`game_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

另一個包含每場比賽中擊球的數據:

CREATE TABLE `ex_atbats` (
 `ab_id` int(11) NOT NULL auto_increment,
 `game` int(11) NOT NULL,
 `team` int(11) NOT NULL,
 `player` int(11) NOT NULL,
 `result` tinyint(1) NOT NULL,
 PRIMARY KEY  (`hit_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

所以我有兩個問題。 讓我們從簡單的版本開始:我想返回一個游戲列表,其中包含每個游戲中有多少個游戲。 所以我想我會這樣做:

SELECT date, home_team, COUNT(h.ab_id) FROM `ex_atbats` h
LEFT JOIN ex_games g ON g.game_id = h.game
GROUP BY g.game_id

此查詢使用filesort / temporary。 有沒有更好的方法來構建這個或索引表來擺脫它?

然后,更棘手的部分:說我現在不僅要包括蝙蝠數量的計數,而且還要包括一個蝙蝠數量的計數,這些蝙蝠之前是同一個團隊的同一結果。 我認為這將是這樣的:

SELECT g.date, g.home_team, COUNT(ab.ab_id), COUNT(ab2.ab_id) FROM `ex_atbats` ab
LEFT JOIN ex_games g ON g.game_id = ab.game
LEFT JOIN ex_atbats ab2 ON ab2.ab_id = ab.ab_id - 1 AND ab2.result = ab.result
GROUP BY g.game_id

這是構造該查詢的正確方法嗎? 這也使用filesort / temporary。

那么完成這些任務的最佳方式是什么?

再次感謝。

短語Using temporary/filesort通常與JOIN操作中使用的索引無關。 有許多示例可以設置所有索引(它們顯示在EXPLAIN中的keykey_len列中),但仍然可以Using temporaryUsing filesort

查看手冊中有關Using temporaryUsing filesort

GROUP BY子句中使用的所有列組合索引可能有助於在某些情況下擺脫Using filesort 如果您還發出ORDER BY ,則可能需要添加更復雜的索引。

如果您有一個龐大的數據集,請考慮使用某些條件(如日期或時間戳)通過實際分區或簡單的WHERE子句對其進行分區

首先,表格的定義很重要。 使用兩個主鍵連接是一回事,另一個是使用一側的主鍵和另一側的非唯一鍵進行連接等等。同樣重要的是,表格使用哪種類型的引擎,因為InnoDB以不同於MyISAM的方式處理主鍵發動機。


我注意到的是,在表test1(c1,c2)組合是唯一的,並且字段不可為空。 這允許您的查詢被重寫為:

SELECT t.c1, t.c2, COUNT(*)
FROM test1 t
LEFT JOIN test2 t2 ON t2.key = t.key
GROUP BY t.key

當為JOINGROUP BY使用相同的字段時,它將給出相同的結果。 請注意,MySQL允許您在不在GROUP BY列表中的SELECT列表字段中使用,而不對它們使用聚合函數。 這在大多數其他系統中是不允許的,並且被某些人視為錯誤。 在這種情況下,雖然這是一個非常好的功能。 每一行都可以由(key)(c1,c2)標識,因此兩個中的哪一個用於分組無關緊要。


另外需要注意的是,當你使用LEFT JOIN ,通常使用右側的連接列進行計數: COUNT(t2.key)而不是COUNT(*) 對於test1中沒有匹配test2任何記錄的記錄,原始查詢將在該列中給出1 ,因為它計算行數,而您可能想要計算test2的相關記錄 - 並在這些情況下顯示0

所以,試試這個查詢並發布EXPLAIN:

SELECT t.c1, t.c2, COUNT(t2.key)
FROM test1 t
LEFT JOIN test2 t2 ON t2.key = t.key
GROUP BY t.key

對於innodb,它將起作用,因為默認情況下索引會篡改您的主鍵。 對於myisam,您必須擁有密鑰,因為索引的最后一列是“key”。 這將為優化器提供相同順序的所有鍵,並且他可以跳過排序。 你不能對索引前綴theN做任何范圍查詢,直接回到filesort。 目前正在努力解決類似的問題

索引有助於加入,但您仍需要進行完整排序才能執行分組。 從本質上講,它仍然必須處理集合中的每個記錄。

當然,添加where子句並限制集合會更快。 它只是不會得到你想要的結果。

除了在整個表上執行分組之外,可能還有其他選項。 我注意到你正在做一個SELECT * - 你想要從查詢中得到什么?

SELECT DISTINCT c1,c2 FROM test t LEFT JOIN test2 t2 ON t2.key = t.key

例如, 可能會跑得更快。 (我意識到這只是一個示例查詢,但是要知道當你不知道最終目標是什么時很難優化!)

編輯 - 在做一些閱讀(http://dev.mysql.com/doc/refman/5.0/en/group-by-optimization.html)時,我了解到,在正確的情況下,索引可以顯着幫助組通過。

我所看到的是它需要是一個排序索引(如BTREE),而不是HASH。 也許:

CREATE INDEX c1c2 IN t (c1, c2) USING BTREE;

可能有幫助。

暫無
暫無

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

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