【问题标题】:What would be the best index for this kind of query in MySQL?MySQL 中这种查询的最佳索引是什么?
【发布时间】:2015-12-09 10:02:59
【问题描述】:

这是我的桌子:

create table page_relation (
     relationid int primary key,
     userid int,
     pageid int,
     registryid int 
);

假设我想多次获取用户每个页面的所有注册表的计数。 这是我要经常运行的查询:

select count(*) as register_count
from page_relation
where userid = 10 
group by pageid;

我需要帮助确定什么是加快查询速度的最佳索引。

到目前为止,我尝试在(userid, pageid) 上使用复合索引,希望 MySQL 将索引用于 group-by,但不幸的是,当我使用 EXPLAIN 时,额外的信息不包含任何“Using index for group-by”信息,只说我正在使用索引并且我正在使用 where。这是否意味着我的索引没有被用于排序?

如果这个索引是聚集的,理论上它不会工作吗?我在想一个 B-Tree、聚集和稀疏索引会很好地完成这项工作......老实说,我期待它甚至是一个覆盖索引,但我真的不知道它是否是。

这是我的解释声明:

# id, select_type, table, type, possible_keys, key, key_len, ref, rows,  Extra
  1, SIMPLE, page_relation, ref, idx_count, idx_count, 4, const, 60, Using where; Using index

仅用于执行此查询的最佳索引是什么?

感谢您的宝贵时间。

【问题讨论】:

  • 很有趣,我也在某个地方遇到过,等待核心 DBA 的回答! BTW,一张表只能有1个聚集索引,而你的表聚集索引被主键占用。你也可以试试 FORCE 索引!
  • 如果我删除主键索引怎么办?我做到了。
  • 索引的强度取决于它的基数。 PK 的基数为 1。没有比这更好的了!
  • 此索引(userid, pageid) 是一个覆盖索引,至于您的解释,没有使用索引进行分组。 dev.mysql.com/doc/refman/5.6/en/explain-output.html

标签: mysql database indexing


【解决方案1】:

可以使用以下两种方法中的任何一种来满足要求:

  1. 复合索引 (userid, pageid)

查询:

select  userid,pageid,count(*) as register_count
from page_relation
where userid = 10 
group by userid,pageid;
  1. 两个索引 - 一个在 userid 上,另一个在 pageid 上

查询:查询将保持与问题中提到的相同。

注意:对于复合键,MySQL 按声明顺序使用索引。例如,复合键(userid,pageid)必须使用字段userid进行过滤或分组,否则索引将被忽略。

第一种方法的好处是它只需要引用一个索引。较少的索引具有更好的写入效率。考虑到空间和时间复杂性,我建议您使用1st approach 进行BTREE 索引。

假设:pageid 字段不唯一。

注意:如果在任何版本的 MySQL 中都没有使用索引,请将 group by 字段也保留在 select clause 中。

【讨论】:

  • 这是第一种方法中的解释:似乎与我的第一个解释相同。那是最佳方法吗? 1、SIMPLE、page_relation、ref、idx_count、idx_count、4、const、60、使用where;使用索引。下面是第二种方式的解释:1、SIMPLE、page_relation、ref、idx_page_relation_userid、idx_page_relation_userid、4、const、60、Using where;使用临时的;使用filesort 第二种方法似乎是使用filesort,是不是很糟糕?
  • @PatriqDesigns:考虑到效率,我已经更新了答案。你的观点是有效的。第一种方法具有预煮的有序索引。第二种方法使用运行时排序。
【解决方案2】:
INDEX(userid, pageid)

是唯一要添加的合理索引。

EXPLAIN 在指示索引(在这种情况下为pageid)是被使用还是被忽略时非常糟糕。您可以尝试EXPLAIN FORMAT=JSON SELECT ... 看看是否可以澄清问题。

INDEX(userid), INDEX(pageid)

用处不大。它会使用其中一个,但不能同时使用两者。它可能会使用 (userid),但这实际上并不比复合索引好,甚至可能更差。

查询本身就令人费解。你得到多行吗?如果没有,请摆脱GROUP BY。如果是这样,您不应该将pageid 添加到SELECT 列表中吗?

我在Index Cookbook 中介绍了大部分内容。

另一个难题...这是一个“关系”表;您的意思是用户标识和页面标识之间的“多对多”映射吗?或者是其他东西。在多:多表中,通常您希望双向使用,因此需要双向使用索引。代理 id 也是无用的,因为 PRIMARY KEY (userid, pageid) 是有保证的。 (请参阅我的食谱。)

我把它升级到PRIMARY KEY,你让事情变得更有效率。

我对“假设”的理解太深了;解决我的一些问题;那我就再啰嗦一下。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    相关资源
    最近更新 更多