所以我梳理了网络,似乎无法找到答案。我有一个具有以下结构的表
Table structure for table `search_tags`
--
CREATE TABLE IF NOT EXISTS `search_tags` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`LOOK_UP_TO_CAT_ID` int(11) NOT NULL,
`SEARCH_TAG` text COLLATE utf8_unicode_520_ci NOT NULL,
`DATE` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`SOURCE` varchar(225) COLLATE utf8_unicode_520_ci NOT NULL,
`SOURCE_ID` int(11) NOT NULL,
`WEIGHT` int(11) NOT NULL DEFAULT '1000',
PRIMARY KEY (`ID`),
KEY `LOOK_UP_TO_CAT_ID` (`LOOK_UP_TO_CAT_ID`),
KEY `WEIGHT` (`WEIGHT`),
FULLTEXT KEY `SEARCH_TAG` (`SEARCH_TAG`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_520_ci AUTO_INCREMENT=1 ;
该表位于800000多行并且正在增长。
当我在LOOK_UP_TO_CAT_ID
上使用组运行查询时,查询运行需要1-2秒。我需要通过连接到其他表来运行此基础的多个版本,但这似乎是瓶颈所在,因为添加连接到这不会减慢它
SELECT LOOK_UP_TO_CAT_ID, WEIGHT
FROM `search_tags`
WHERE `SEARCH_TAG` LIKE '%metallica%'
GROUP BY `LOOK_UP_TO_CAT_ID`
删除GROUP BY
会将查询时间降低到0.1,这似乎更容易接受,但后来我重复了。
在分组中使用说明表明它创建了一个临时表而不是使用索引
+----+-------------+-------------+------+-------------------+------+---------+------+--------+----------------------------------------------+--+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | |
+----+-------------+-------------+------+-------------------+------+---------+------+--------+----------------------------------------------+--+
| 1 | SIMPLE | search_tags | ALL | LOOK_UP_TO_CAT_ID | NULL | NULL | NULL | 825087 | Using where; Using temporary; Using filesort | |
+----+-------------+-------------+------+-------------------+------+---------+------+--------+----------------------------------------------+--+
所以我不确定mysql是否在这里做正确的事情,但至少对我来说,不使用索引似乎是错误的。加快查询速度的最佳原因是什么?
编辑:
以下是我的数据示例:
+----+-------------------+----------------------------------+------------+---------------+-----------+--------+
| ID | LOOK_UP_TO_CAT_ID | SEARCH_TAG | DATE | SOURCE | SOURCE_ID | WEIGHT |
+----+-------------------+----------------------------------+------------+---------------+-----------+--------+
| 1 | 521 | METALLICA | 2017-02-18 | artist | 15 | 1 |
| 2 | 521 | METALLICA - NOTHING ELSE MATTERS | 2017-02-18 | tracklisting | 22 | 2 |
| 3 | 522 | METALLICA | 2017-02-18 | artist | 15 | 1 |
| 4 | 522 | METALLICA - ST. Anger | 2017-02-18 | product_title | 522 | 2 |
+----+-------------------+----------------------------------+------------+---------------+-----------+--------+
期望的结果
+-------------------+--------+
| LOOK_UP_TO_CAT_ID | WEIGHT |
+-------------------+--------+
| 521 | 1 |
| 522 | 1 |
+-------------------+--------+
答案 0 :(得分:0)
在某种程度上,你的问题没有意义。您有一个全文索引,但正在使用LIKE
进行表扫描。您需要使用MATCH()
来使用全文索引。
我真正想到的是返回的数据量很大。在没有order by
或group by
的情况下执行查询时,会在生成结果时返回结果。您会看到结果,因为早期扫描的某些行符合您的条件。
group by
/ order by
需要阅读所有结果。
您可以通过count(*)
代替select
:
SELECT COUNT(*)
FROM `search_tags`
WHERE `SEARCH_TAG` LIKE '%metallica%';
我怀疑这可能需要更长时间。
您可以使用相关子查询来消除重复消除的性能损失:
SELECT st.LOOK_UP_TO_CAT_ID, st.WEIGHT
FROM `search_tags` st
WHERE `SEARCH_TAG` LIKE '%metallica%' AND
st.id = (SELECT MIN(st2.id) FROM search_tags st2 WHERE st2.LOOK_UP_TO_CAT_ID = st.LOOK_UP_TO_CAT_ID);
这特别需要search_tags(LOOK_UP_TO_CAT_ID, ID)
的索引来提高性能。
但是,您可能希望使用MATCH()
来利用全文索引。
答案 1 :(得分:0)
为您提供一些建议。
SEARCH_TAG LIKE '%metallica%'
永远不会使用索引。模式haystack like '%needle'
(前导%
)要求MySQL检查列中的每个值以进行匹配。 haystack LIKE 'needle%'
(尾随%
)没有此问题。
您的SEARCH_TAG
列上有a FULLTEXT
index,因此请使用它! WHERE MATCH('metallica') AGAINST SEARCH_TAG
是您需要的WHERE子句的形式。
您的表上有很多单列索引。这些通常对于提高查询速度没有帮助,除非它们恰好与您尝试做的完全匹配。您最好使用专为您正在运行的查询设计的compound covering indexes。
您问题中的示例查询是
SELECT LOOK_UP_TO_CAT_ID, WEIGHT
FROM search_tags
WHERE SEARCH_TAG LIKE '%metallica%'
GROUP BY LOOK_UP_TO_CAT_ID
如果你把它改成这样,它会使SQL更有意义并且运行得更快。
SELECT LOOK_UP_TO_CAT_ID, MAX(WEIGHT)
FROM search_tags
WHERE SEARCH_TAG LIKE 'metallica%'
GROUP BY LOOK_UP_TO_CAT_ID
(注意我摆脱了领先的%
。)
如果在(SEARCH_TAG, LOOK_UP_CAT_ID, WEIGHT)
上添加覆盖索引的化合物,此查询将变得非常快。可以从索引中满足整个查询。 MySQL随机访问索引以查找您的SEARCH_TAG,然后执行loose index scan以获取您请求的结果。
(旁白:当您在filesort
或EXPLAIN
查询的GROUP BY
输出中看到ORDER BY
时,请不要担心。它的一部分MySQL满足查询的方式。filesort
中的文件并不一定意味着硬盘上的文件速度很慢。)