为什么此查询(以及许多类似的变体)不会在'标记'表上使用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显示正在使用索引(在测试数据库运行,因此在 '标签' 行低,但仍然是一个全表扫描):
| 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个小时的工作已经让我无处。任何建议是受欢迎的。
编辑:
我可以看到使用子查询的第一查询不会使用索引由于一些答复,但是这是被用作它跑了两次只内底部的查询一样快加入。
举例来说,请求中有70k行(全部带有索引ASIN),标签中有700k行,标签中有95K个不同的ASIN,每个标签中有不少于10个不同的标签记录。
如果用户有10个请求,我只希望这10个ASIN中的标签被列出和计数。在我看来,这应该使用tags.idx_ASIN,并且应该从标签表中查找至多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!不同的字符集和归类。我将纠正并重试!
后来:
这得到了它。查询从10秒下降到0.006秒。感谢大家让我以不同的方式看待这个问题。
可能是因为内部选择 - 索引不适用于子查询 – galchen
底部的原始查询没有子查询,但仍执行全表扫描。 – markdwhite
这可能是因为MySQL不考虑重新排序的花费,而是使用索引所节省的成本。尝试删除'order by'和/或'group by'来查看这是否会导致MySQL使用您的索引。 – jswolf19