2012-01-16 53 views
2

我剛在應用程序中看到一個非常慢的查詢。表'新聞'有超過600.000條記錄。MySQL:優化對記錄範圍的搜索。

當我執行:

SELECT news.id FROM `news` WHERE (newstime between '2012-01-16 00:00:00' AND '2012-01-16 23:59:59') AND ((MATCH(titolo, testo) AGAINST('"Public Administration" "SOMETHING" "ELSE" "ROMA" "MILANO"' IN BOOLEAN MODE))) ORDER BY newstime DESC LIMIT 23 OFFSET 0; 
23 rows in set (26.32 sec) 

出於某種原因,MySQL是不執行範圍選擇(只有10.000記錄每一天),它看起來像它的搜索對整個表,因爲當我從子查詢選擇:

SELECT id FROM(SELECT * from news where newstime between '2012-01-16 00:00:00' AND '2012-01-16 23:59:59') as N where ((MATCH(titolo, testo) AGAINST('"Public Administration" "FIAT" "SOMETHING" "ELSE" "ROMA" "MILANO"' IN BOOLEAN MODE))) ORDER BY newstime DESC LIMIT 23 OFFSET 0; 

23 rows in set (0.09 sec) 

我的查詢在0.09秒後返回!

26→0.09秒。

我認爲MySQL將足夠智能,通過newstime選擇記錄範圍,然後進行全文搜索,但看起來不是這樣。這是正常的嗎?或者我應該嘗試還是優化第一個查詢?當我寫解釋#1它告訴:

mysql> explain SELECT news.id FROM `news` WHERE (newstime between '2012-01-16 00:00:00' AND '2012-01-16 23:59:59') AND ((MATCH(titolo, testo) AGAINST('"Public Administration" "FIAT" "SOMETHING" "ELSE" "ROMA" "MILANO"' IN BOOLEAN MODE))) ORDER BY newstime DESC LIMIT 23 OFFSET 0; 
+----+-------------+-------+----------+--------------------------------+---------+---------+------+------+-----------------------------+ 
| id | select_type | table | type  | possible_keys     | key  | key_len | ref | rows | Extra      | 
+----+-------------+-------+----------+--------------------------------+---------+---------+------+------+-----------------------------+ 
| 1 | SIMPLE  | news | fulltext | index_news_on_newstime,alltext | alltext | 0  |  | 1 | Using where; Using filesort | 
+----+-------------+-------+----------+--------------------------------+---------+---------+------+------+-----------------------------+ 

爲什麼使用全文本鍵而不是新的?

顯示創建表的消息是如下:

CREATE TABLE `news` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `titolo` varchar(255) DEFAULT NULL, 
    `testo` mediumtext, 
    `newstime` datetime NOT NULL, 
    `created_at` datetime DEFAULT NULL 
    PRIMARY KEY (`id`), 
    KEY `index_news_on_newstime` (`newstime`), 
    FULLTEXT KEY `alltext` (`titolo`,`testo`) 
) ENGINE=MyISAM AUTO_INCREMENT=1846714 DEFAULT CHARSET=utf8 | 

這是爲什麼?

回答

5

「爲什麼?」的答案只是MySQL查詢優化器不完美。有時它會選擇較不理想的指數。你可以告訴MySQL的糾正這種與index hints

SELECT news.id 
FROM `news` 
USE INDEX (index_news_on_newstime) 
WHERE (newstime between '2012-01-16 00:00:00' AND '2012-01-16 23:59:59') 
    AND ((MATCH(titolo, testo) AGAINST('"Public Administration" "SOMETHING" "ELSE" "ROMA" "MILANO"' IN BOOLEAN MODE))) 
ORDER BY newstime DESC LIMIT 23 OFFSET 0; 

從文檔使用哪個索引: 「你也可以使用FORCE INDEX,其作用像USE INDEX(起始-TC),但與另外一個表掃描被認爲是非常昂貴的,換句話說,只有在沒有辦法使用某個給定的索引來查找表中的行時才使用表掃描。「

SELECT news.id 
FROM `news` 
FORCE INDEX (index_news_on_newstime) 
WHERE (newstime between '2012-01-16 00:00:00' AND '2012-01-16 23:59:59') 
    AND ((MATCH(titolo, testo) AGAINST('"Public Administration" "SOMETHING" "ELSE" "ROMA" "MILANO"' IN BOOLEAN MODE))) 
ORDER BY newstime DESC LIMIT 23 OFFSET 0; 
+0

謝謝你!你救了我的一天! :) – 2012-01-16 15:11:42