为什么此查询(以及许多类似的变体)不在'tags'表中使用ASIN的索引?它坚持进行全表扫描,即使A只包含几行。由于生产中的“标签”表包含近一百万个条目,因此它会严重破坏查询。
SELECT C.tag, count(C.tag) AS total
FROM
(
SELECT B.*
FROM
(
SELECT ASIN FROM requests WHERE user_id=9
) A
INNER JOIN tags B USING(ASIN)
) C
GROUP BY C.tag ORDER BY total DESC
EXPLAIN显示没有使用索引(在测试数据库上运行,因此'tags'中的行很低,但仍然是全表扫描):
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 0 | const row not found |
| 2 | DERIVED | <derived3> | ALL | NULL | NULL | NULL | NULL | 28 | |
| 2 | DERIVED | B | ALL | NULL | NULL | NULL | NULL | 2593 | Using where; Using join buffer |
| 3 | DERIVED | borrowing_requests | ref | idx_user_id | idx_user_id | 5 | | 27 | Using where
索引:
| book_tags | 1 | asin | 1 | ASIN | A | 432 | NULL | NULL | | BTREE | |
| book_tags | 1 | idx_tag | 1 | tag | A | 1296 | NULL | NULL | | BTREE | |
| book_tags | 1 | idx_updated_on | 1 | updated_on | A | 518 | NULL | NULL | | BTREE
查询是从具有相同问题的INNER JOIN重写的:
SELECT tag, count(tag) AS total
FROM tags
INNER JOIN requests ON requests.ASIN=tags.ASIN
WHERE user_id=9
GROUP BY tag
ORDER BY total DESC
说明:
| 1 | SIMPLE | tags | ALL | NULL | NULL | NULL | NULL | 2593 | Using temporary; Using filesort |
| 1 | SIMPLE | requests | ref | idx_ASIN,idx_user_id | idx_ASIN | 33 | func | 3 | Using where
我明白这是一个我缺少的真正基本点,但大约4个小时的工作让我无处可去。欢迎任何建议。
编辑:
我可以看到使用子查询的第一个查询由于某些回复而不会使用索引,但是这被使用,因为它的运行速度是只有INNER JOIN的底部查询的两倍。
例如,请求中有70k行(全部带有索引的ASIN),标签中有700k行,标签中有95k个不同的ASIN,每个都有少于10个不同的标记记录。
如果用户有10个请求,我只希望列出并计算来自这10个ASIN的标签。在我看来,这应该使用tags.idx_ASIN,并且应该从tags表中查找最多100行(10个ASIN,每个最多包含10个标签)。
我错过了什么......我只是看不出来。
编辑:
请求CREATE TABLE:
CREATE TABLE IF NOT EXISTS `requests` (
`bid` int(40) NOT NULL AUTO_INCREMENT,
`user_id` int(20) DEFAULT NULL,
`ASIN` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL,
`status` enum('active','inactive','pending','deleted','completed') COLLATE utf8_unicode_ci NOT NULL,
`added_on` datetime NOT NULL,
`status_changed_on` datetime NOT NULL,
`last_emailed` datetime DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`bid`),
KEY `idx_ASIN` (`ASIN`),
KEY `idx_status` (`status`),
KEY `idx_added_on` (`added_on`),
KEY `idx_user_id` (`user_id`),
KEY `idx_status_changed_on` (`status_changed_on`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=149380 ;
标签CREATE TABLE
CREATE TABLE IF NOT EXISTS `tags` (
`ASIN` varchar(10) NOT NULL,
`tag` varchar(50) NOT NULL,
`updated_on` datetime NOT NULL,
KEY `idx_tag` (`tag`),
KEY `idx_updated_on` (`updated_on`),
KEY `idx_asin` (`ASIN`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
标签上没有主键。我通常没有没有主键的表,但没有看到这个需要。这可能是一个问题吗?
AHA!不同的字符集和校对。我会更正并再试一次!
随后:
得到了它。查询从10secs下降到0.006secs。感谢大家让我以不同的方式看待它。
答案 0 :(得分:1)
MySQL不会索引子查询。如果希望索引提高查询性能,请将其重写为不使用子查询。
答案 1 :(得分:0)
尝试颠倒原始查询中表格的顺序:
SELECT tag, count(tag) AS total
FROM requests
INNER JOIN tags ON requests.ASIN=tags.ASIN
WHERE user_id=9
GROUP BY tag
ORDER BY total DESC
答案 2 :(得分:0)
AHA!不同的字符集和校对。我会更正并再试一次!
随后:
得到了它。查询从10secs下降到0.006secs。感谢大家让我以不同的方式看待它。