2013-12-17 82 views
0

我忙於探索GROUP BY優化。在經典的「最高薪水每出發」查詢。突然奇怪的結果。下面的轉儲從我的控制檯去。這兩個解釋之間沒有發佈命令。只過了一段時間。有沒有辦法暗示mysql使用使用索引的組 -

mysql> explain select name, t1.dep_id, salary 
     from emploee t1 
     JOIN (select dep_id, max(salary) msal 
       from emploee 
       group by dep_id 
     ) t2 
     ON t1.salary=t2.msal and t1.dep_id = t2.dep_id 
     order by salary desc; 
+----+-------------+------------+-------+---------------+--------+---------+-------------------+------+---------------------------------+ 
| id | select_type | table  | type | possible_keys | key | key_len | ref    | rows | Extra | 
+----+-------------+------------+-------+---------------+--------+---------+-------------------+------+---------------------------------+ 
| 1 | PRIMARY  | <derived2> | ALL | NULL   | NULL | NULL | NULL    | 4 | Using temporary; Using filesort | 
| 1 | PRIMARY  | t1   | ref | dep_id  | dep_id | 8  | t2.dep_id,t2.msal | 1 | | 
| 2 | DERIVED  | emploee | index | NULL   | dep_id | 8  | NULL    | 84 | Using index | 
+----+-------------+------------+-------+---------------+--------+---------+-------------------+------+---------------------------------+ 
3 rows in set (0.00 sec) 

mysql> explain select name, t1.dep_id, salary 
     from emploee t1 
     JOIN ( select dep_id, max(salary) msal 
       from emploee 
       group by dep_id 
     ) t2 
     ON t1.salary=t2.msal and t1.dep_id = t2.dep_id 
     order by salary desc; 
+----+-------------+------------+-------+---------------+--------+---------+-------------------+------+---------------------------------+ 
| id | select_type | table  | type | possible_keys | key | key_len | ref    | rows | Extra | 
+----+-------------+------------+-------+---------------+--------+---------+-------------------+------+---------------------------------+ 
| 1 | PRIMARY  | <derived2> | ALL | NULL   | NULL | NULL | NULL    | 4 | Using temporary; Using filesort | 
| 1 | PRIMARY  | t1   | ref | dep_id  | dep_id | 8  | t2.dep_id,t2.msal | 3 | | 
| 2 | DERIVED  | emploee | range | NULL   | dep_id | 4  | NULL    | 9 | Using index for group-by | 
+----+-------------+------------+-------+---------------+--------+---------+-------------------+------+---------------------------------+ 
3 rows in set (0.00 sec) 

正如您可能注意到的那樣,它在第二次運行時檢查了十倍少的行。我認爲這是因爲一些內部計數器發生了變化。但我不想依賴這些櫃檯。所以 - 是否有一種方法可以提示mysql使用「僅使用index for group」行爲?

或者 - 如果我的猜測是錯誤的 - 是否有任何其他解釋的行爲和如何解決它?

CREATE TABLE `emploee` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) DEFAULT NULL, 
    `dep_id` int(11) NOT NULL, 
    `salary` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `dep_id` (`dep_id`,`salary`) 
) ENGINE=InnoDB AUTO_INCREMENT=85 DEFAULT CHARSET=latin1 | 
+-----------+ 
| version() | 
+-----------+ 
| 5.5.19 | 
+-----------+ 

回答

3

嗯,顯示指數的基數可能會有幫助,但要記住:range的通常是然後index ES那裏。

因爲它認爲它可以匹配第一個完整的索引,它使用完整的索引。在第二種情況下,它會降低索引並達到一個範圍,但會猜測總行數滿足較大的範圍大大低於較小的全索引,因爲所有基數都已更改。比較一下:爲什麼「AA」匹配84行,但「A [任意字符]」只匹配9(注意它使用第一個字節的8個字節,第二個字節使用4個字節)?第二個實際上不會讀取更少的行,EXPLAIN只是在更新索引的元數據後猜測行數。也不是那EXPLAIN確實不是告訴你什麼查詢做什麼,但可能會做什麼。

更新基數可以或will occur when

在一個表中的每一個索引的基數(不同的密鑰值的數量)是當一個表被打開時,在SHOW TABLE狀況,分析表,並在計算出的其他情況(比如表格變化太大時)。請注意,如果自動重新刷新設置設置爲開啓(默認),則mysql客戶端啓動時將打開所有表並重新估計統計信息。

因此,假設「在任何時候」,由於「變化太大了」,是的,與mysql客戶連接可以改變在選擇服務器的索引行爲。另外:在超時之後失去連接後重新連接mysql客戶端連接自動rehash AFAIK。如果你想讓mysql幫忙找到正確的方法,那麼偶爾運行ANALYZE TABLE,特別是在大量更新之後。如果你認爲它猜測的基數常常是錯誤的,你可以用alter the number of pages來猜測一些統計數據,但記住一個更高的數字意味着該基數的更長時間的運行更新,而當你想要「數據在很多操作的桌子上變成了很多'。

TL; DR:它猜測行的方式不同,但如果數據可行,您實際上更喜歡第一種行爲。

添加: 在此previously linked page,我們可以大概也覺得爲什麼特別dep_id可能有這樣的問題:

像1或2小值會導致基數

的非常不準確的估計

我可以想象不同的dep_id的數量通常很小,而且我確實觀察到非「非彈性」基數 - 與我自己的數據庫中的行數相比,具有相當小範圍的唯一索引。它很容易猜出數百個1-10的範圍,然後再下一次,只是基於它選取的具體樣本頁面&某些算法試圖推斷。

相關問題