2012-10-16 48 views
2

我有以下簡單的MySQL查詢:簡單的MySQL查詢問題

SELECT SQL_NO_CACHE mainID 
FROM tableName 
WHERE otherID3=19 
AND dateStartCol >= '2012-08-01' 
AND dateStartCol <= '2012-08-31'; 

當我運行這個需要0.29秒帶回36074個結果。當我增加日期以帶回更多結果時(65703),它運行在0.56。當我在同一臺服務器上但在不同的表上運行其他類似的SQL查詢時(某些表更大),結果大約在0.01秒後回來。

雖然0.29並不慢 - 這是複雜查詢的基本部分,並且此計時意味着它不可縮放。

請參閱下面的表格定義和索引。

我知道這不是服務器負載,因爲我在開發服務器上有相同的問題,使用很少。

+---------------------------+--------------+------+-----+---------+----------------+ 
| Field      | Type   | Null | Key | Default | Extra   | 
+---------------------------+--------------+------+-----+---------+----------------+ 
| mainID     | int(11)  | NO | PRI | NULL | auto_increment | 
| otherID1     | int(11)  | NO | MUL | NULL |    | 
| otherID2     | int(11)  | NO | MUL | NULL |    | 
| otherID3     | int(11)  | NO | MUL | NULL |    | 
| keyword     | varchar(200) | NO | MUL | NULL |    | 
| dateStartCol    | date   | NO | MUL | NULL |    | 
| timeStartCol    | time   | NO | MUL | NULL |    | 
| dateEndCol    | date   | NO | MUL | NULL |    | 
| timeEndCol    | time   | NO | MUL | NULL |    | 
| statusCode    | int(1)  | NO | MUL | NULL |    | 
| uRL      | text   | NO |  | NULL |    | 
| hostname     | varchar(200) | YES | MUL | NULL |    | 
| IPAddress     | varchar(25) | YES |  | NULL |    | 
| cookieVal     | varchar(100) | NO |  | NULL |    | 
| keywordVal    | varchar(60) | NO |  | NULL |    | 
| dateTimeCol    | datetime  | NO | MUL | NULL |    | 
+---------------------------+--------------+------+-----+---------+----------------+ 


+--------------------+------------+-------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table    | Non_unique | Key_name      | Seq_in_index | Column_name    | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+--------------------+------------+-------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+ 
| tableName   |   0 | PRIMARY      |   1 | mainID     | A   |  661990 |  NULL | NULL |  | BTREE  |   | 
| tableName   |   1 | idx_otherID1     |   1 | otherID1     | A   |  330995 |  NULL | NULL |  | BTREE  |   | 
| tableName   |   1 | idx_otherID2     |   1 | otherID2     | A   |   25 |  NULL | NULL |  | BTREE  |   | 
| tableName   |   1 | idx_otherID3     |   1 | otherID3     | A   |   48 |  NULL | NULL |  | BTREE  |   | 
| tableName   |   1 | idx_dateStartCol    |   1 | dateStartCol    | A   |   187 |  NULL | NULL |  | BTREE  |   | 
| tableName   |   1 | idx_timeStartCol    |   1 | timeStartCol    | A   |  73554 |  NULL | NULL |  | BTREE  |   | 
|tableName   |   1 | idx_dateEndCol     |   1 | dateEndCol     | A   |   188 |  NULL | NULL |  | BTREE  |   | 
|tableName   |   1 | idx_timeEndCol     |   1 | timeEndCol     | A   |  73554 |  NULL | NULL |  | BTREE  |   | 
| tableName   |   1 | idx_keyword     |   1 | keyword     | A   |  82748 |  NULL | NULL |  | BTREE  |   | 
| tableName   |   1 | idx_hostname     |   1 | hostname     | A   |  2955 |  NULL | NULL | YES | BTREE  |   | 
| tableName   |   1 | idx_dateTimeCol    |   1 | dateTimeCol    | A   |  220663 |  NULL | NULL |  | BTREE  |   | 
| tableName   |   1 | idx_statusCode    |   1 | statusCode     | A   |   2 |  NULL | NULL |  | BTREE  |   | 
+--------------------+------------+-------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+ 

explain輸出:

+----+-------------+-----------+-------+----------------------------------+-------------------+---------+------+-------+----------+-------------+ 
| id | select_type | table  | type | possible_keys     | key    | key_len | ref | rows | filtered | Extra  | 
+----+-------------+-----------+-------+----------------------------------+-------------------+---------+------+-------+----------+-------------+ 
| 1 | SIMPLE  | tableName | range | idx_otherID3,idx_dateStartCol | idx_dateStartCol | 3  | NULL | 66875 | 75.00 | Using where | 
+----+-------------+-----------+-------+----------------------------------+-------------------+---------+------+-------+----------+-------------+ 
+0

添加解釋結果。 –

+0

你嘗試過'和dateStartCol BETWEEN'2012-08-01' AND'2012-08-31''。不知道它是否會有所幫助,但值得一試。 – Bojangles

+0

我已經嘗試了BETWEEN,並且在時間上沒有顯着差異(從0.29到0.28)。 -還是)感謝你的建議。 – mh1

回答

1

說明檢查的key_buffer_size和innodb_buffer_pool_size如果這真的是你的查詢(和同樣不是一個簡化版本),那麼這應該爲達到最佳效果:

CREATE INDEX table_ndx on tableName(otherID3, dateStartCol, mainID); 

的第一個索引進入意味着WHERE的第一場比賽非常快;這同樣適用於dateStartCol。第三個字段非常小,並且不會顯着減慢索引,但是可以立即在索引中找到所需的數據,並且根本無法訪問表。

重要的是,鍵是在相同的索引。在你發佈的EXPLAIN中,每個密鑰都在它自己的索引中,所以即使MySQL選擇最佳索引,性能也不會是最佳的。我會嘗試使用較少的索引,因爲它們也有成本(無恥插件:Can Indices actually decrease SELECT performance?)。

0

如果這是一個經常性的或者重要的查詢,然後創建一個多列索引:

CREATE INDEX index_name ON tableName (otherID3, dateStartCol) 

刪除使用的索引,非,因爲他們使表變化比較昂貴。

順便說一句,你不需要兩個單獨的日期和時間列。您可以在datetimetimestamp類型中進行組合。少一列,少索引。

explain輸出顯示它選擇了dateStartCol指數,所以你可以嘗試我上述的建議相反:

CREATE INDEX index_name ON tableName (dateStartCol, otherID3) 

注意查詢的dateStartCol條件仍然會得到行的75%,所以沒有太大的起色,如果任何,在使用該單一索引。

​​有多獨特?如果沒有太多的重複​​你可以hint引擎來使用它。

+0

我試過這樣做,但它需要從0.29到0.25的查詢時間。也使用所有索引 - 不一定在此SQL中,但在其他報告中,因此它們不能被刪除。 – mh1

+0

@ mh1基於'explain'編輯 –

+0

的確,應該這樣做。但是,我非常確定該索引中的字段順序應該不重要,因爲在AND查詢中,MySQL可以決定對它們進行重新排序。如果這有所作爲,它甚至可能是一個錯誤。 –

0

首先嚐試添加正確的密鑰。好像dateStartCol比otherID3

更有選擇性
ALTER TABLE tableName ADD KEY idx_dates(dateStartCol, dateStartCol) 

二 - 請確保您只選擇您需要通過添加LIMIT子句的選擇行。這將會應對查詢。嘗試這樣的:

SELECT SQL_NO_CACHE mainID FROM TABLENAME WHERE otherID3 = 19 AND dateStartCol> = '2012-08-01' AND dateStartCol < = '2012-08-31' LIMIT 10;

還請確保您的MySQL正確調整。您可能希望在http://astellar.com/2011/12/why-is-stock-mysql-slow/

+0

LIMIT不會有太大區別,因爲它將首先執行相同的查詢,然後僅返回一部分結果。由於這只是一些ID的查詢,所以數據的傳輸不會是昂貴的部分。 –

+0

您對數據傳輸是正確的,但在某些情況下,MySQL會在達到限制時停止讀取數據。看來IO在這種情況下很大程度上涉及它可能會有所幫助。但無論如何,300ms對於這種類型的查詢來說太長了,不管LIMIT如何 – vfedorkov