mysql 多列索引不起作用(如预期)?
我有一个这样的表,
CREATE TABLE IF NOT EXISTS `tbl_folder` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`owner_userid` int(11) NOT NULL,
`name` varchar(63) NOT NULL,
`description` text NOT NULL,
`visibility` tinyint(4) NOT NULL DEFAULT '2',
`num_items` int(11) NOT NULL DEFAULT '0',
`num_subscribers` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `owner_userid` (`owner_userid`),
KEY `vis_sub_item` (`visibility`,`num_subscribers`,`num_items`)
) ENGINE=InnoDB
因为我有一个关于可见性、num_subscribers 和 num_items 的索引,我希望只需要查看前 15 行,相反,EXPLAIN 说 55856 行。有什么想法吗?谢谢
EXPLAIN SELECT t.id, name, description, owner_userid, num_items, num_subscribers
FROM `tbl_folder` `t`
WHERE visibility =2
ORDER BY `t`.`num_subscribers` DESC , `t`.`num_items` DESC
LIMIT 15
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t ref vis_sub_item vis_sub_item 1 const 55856 Using where
I have a table like this
CREATE TABLE IF NOT EXISTS `tbl_folder` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`owner_userid` int(11) NOT NULL,
`name` varchar(63) NOT NULL,
`description` text NOT NULL,
`visibility` tinyint(4) NOT NULL DEFAULT '2',
`num_items` int(11) NOT NULL DEFAULT '0',
`num_subscribers` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `owner_userid` (`owner_userid`),
KEY `vis_sub_item` (`visibility`,`num_subscribers`,`num_items`)
) ENGINE=InnoDB
since I have an index on visibility, num_subscribers and num_items, I expect that only the first 15 rows only have to be looked at, instead, EXPLAIN says 55856 rows. Any idea? Thanks
EXPLAIN SELECT t.id, name, description, owner_userid, num_items, num_subscribers
FROM `tbl_folder` `t`
WHERE visibility =2
ORDER BY `t`.`num_subscribers` DESC , `t`.`num_items` DESC
LIMIT 15
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t ref vis_sub_item vis_sub_item 1 const 55856 Using where
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的 3 字段索引看起来不错,并且
EXPLAIN
很有希望。虽然它说“55856 行”,但这只是
EXPLAIN
提供的估计。由于
key_len =1
,您知道它使用复合索引的第一个字节作为相等/引用。由于您的
Extra
字段中没有提到文件排序,因此您知道ORDER BY
/排序 由索引处理。如果您检查
handler_%
会话统计信息,您将更好地了解实际读取了多少行。附带想法:
既然您知道最终会访问磁盘来检索行,那么如果 99% 的数据具有
visibility=2
(只是推测),那么您'仅在num_subscribers
上使用复合索引就可能获得同样好/快的结果num_items
。或者,如果您在 num_subscribers 上有一个索引,则可以说同样好/快,具体取决于它的基数/唯一性。Your 3 field index looks good and the
EXPLAIN
is promising.Although it says "55856 rows", that is just an estimate provided by
EXPLAIN
.Since
key_len =1
, you know it's using the first byte of your compound index as an equality/reference.Since there is no filesort mentioned in your
Extra
field, you know that theORDER BY
/sorting is being handled by the index.If you check your
handler_%
session stats, you'll have a better idea of how many rows are actually being read.Side Thoughts:
Since you know you're ultimately going to hit disk to retrieve your rows, if 99% of your data has
visibility=2
(just speculating), you'd likely get as equally good/fast results with a compound index just onnum_subscribers
&num_items
. Or arguably as good/fast if you has a single index onnum_subscribers
, depending on it's cardinality/uniqueness.我认为
EXPLAIN
不会查看OFFSET
或LIMIT
子句。EXPLAIN
应该指示查询将如何执行、它使用什么键、如何连接表等。LIMIT
子句有点像后查询修饰符。 ..现在我们知道我们想要什么,只给他们第一个这么多。因此,行字段包含查询中可能存在的行数。从那里,OFFSET
和LIMIT
将选择您想要的特定值。我认为,如果您在没有
EXPLAIN
的情况下执行SELECT
,您将获得所需的记录数。I don't think that
EXPLAIN
looks at theOFFSET
orLIMIT
clause.EXPLAIN
is supposed to indicate how the query would be executed, what keys it used, how tables are joined, etc. TheLIMIT
clause is sort of like a post query modifier...now that we know what we want, only give em the first so many. So, the rows field contains the number of possible rows that exist in the query. From there,OFFSET
andLIMIT
would select the specific ones you want.I'm figuring that if you executed your
SELECT
withoutEXPLAIN
, you'd get the number of records you wanted.是的,问题是你的索引不正确。我的意思是您对所有 3 个字段建立了索引,而您的选择查询仅检查一个字段。在 MySQL 中,单独索引 2 行与同时索引 3 行是不同的。
尝试
yes, the problem is that your index is not correct. I mean you indexed all 3 fields and your select query only checks for one. In MySQL indexing 2 rows separately is different from indexing 3 rows together.
Try