mysql 多列索引不起作用(如预期)?

发布于 2024-10-06 20:54:31 字数 962 浏览 3 评论 0原文

我有一个这样的表,

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

司马昭之心 2024-10-13 20:54:31

您的 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 the ORDER 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 on num_subscribers & num_items. Or arguably as good/fast if you has a single index on num_subscribers, depending on it's cardinality/uniqueness.

静待花开 2024-10-13 20:54:31

我认为 EXPLAIN 不会查看 OFFSETLIMIT 子句。 EXPLAIN 应该指示查询将如何执行、它使用什么键、如何连接表等。LIMIT 子句有点像后查询修饰符。 ..现在我们知道我们想要什么,只给他们第一个这么多。因此,行字段包含查询中可能存在的行数。从那里,OFFSETLIMIT 将选择您想要的特定值。

我认为,如果您在没有 EXPLAIN 的情况下执行 SELECT ,您将获得所需的记录数。

I don't think that EXPLAIN looks at the OFFSET or LIMIT clause. EXPLAIN is supposed to indicate how the query would be executed, what keys it used, how tables are joined, etc. The LIMIT 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 and LIMIT would select the specific ones you want.

I'm figuring that if you executed your SELECT without EXPLAIN, you'd get the number of records you wanted.

苹果你个爱泡泡 2024-10-13 20:54:31

是的,问题是你的索引不正确。我的意思是您对所有 3 个字段建立了索引,而您的选择查询仅检查一个字段。在 MySQL 中,单独索引 2 行与同时索引 3 行是不同的。

尝试

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_index` (`visibility`),
  KEY `vis_sub_item` (`num_subscribers`,`num_items`)
) ENGINE=InnoDB

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

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_index` (`visibility`),
  KEY `vis_sub_item` (`num_subscribers`,`num_items`)
) ENGINE=InnoDB
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文