MySQL:优化对记录范围的搜索。

标签 mysql sql optimization range full-text-search

我刚刚在我的应用程序中看到一个非常慢的查询。表“新闻”有超过 600.000 条记录。

当我执行时:

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会足够智能,可以按新闻时间选择记录范围,然后进行全文搜索,但看起来并非如此。正常吗?或者我应该尝试仍然优化第一个查询?当我写解释 #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 |

这是为什么呢?

最佳答案

“为什么?”的答案只是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 (index_list),但表扫描被认为是非常昂贵的。换句话说,只有在无法进行表扫描的情况下才使用表扫描。使用给定索引之一查找表中的行。”

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;

关于MySQL:优化对记录范围的搜索。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8881331/

相关文章:

mysql - 如何生成没有外键的ER图(MySQL)?

Java:在这里包含一个 else 更快吗?还是更好的练习?

html - 显示单个图像还是显示图像拼贴的一部分?

MySQL日期列以日、月、年

mysql - 将测试数据库重建为生产数据库

php - 如何将mysql改为mysqli?

sql - MS SQL 临时表循环

mysql - SQL查询: Need to speed up this query that diffs against two databases

c - 在 C 中使用输入参数而不是局部变量是否更有效?

php - 如何在mysql数据库中插入html代码?