具有复杂 MySQL 查询的索引

Posted

技术标签:

【中文标题】具有复杂 MySQL 查询的索引【英文标题】:Index with a Complex MySQL Query 【发布时间】:2013-07-07 13:54:40 【问题描述】:

我有以下疑问:

SELECT venues.venue_name, count( distinct checkin.user_id ) AS total_count, category_id
    FROM checkin
    INNER JOIN venues ON checkin.internal_venue_id = venues.venue_primary_id
    WHERE checkin.item_id = '3783'
    and is_category_valid = 1 and created_at >= DATE_SUB('2013-07-07 12:35:06', INTERVAL 5 DAY)
    GROUP BY checkin.internal_venue_id
    ORDER BY total_count DESC
    LIMIT 10;

我正在努力处理此查询所需的索引。是否正确的索引:

checkin: (internal_venue_id, item_id, is_category_valid, created_at, user_id)

或者还有其他更理想的查询路径吗?

【问题讨论】:

【参考方案1】:

您建议的索引是相关的。

但没有“正确”或“最佳”索引本身这样的东西,您需要考虑表的完整结构以及基数。例如,is_category_valid = 1 有多少条记录(按比例)?如果大多数记录都满足这个条件,那么这个字段上的索引就没什么用了。

基本思想是按“重要性”的顺序包含列,也就是说,首先在最具辨别力的列上。例如,如果大多数类别都是“有效的”,我会将 is_category_valid 列推到索引的末尾。

(出现在GROUP BYORDER BY 子句中的列有一个例外,但你已经知道了,所以看起来)

您应该查看查询执行计划 (EXPLAIN SELECT [your query here]) 并查看查询是如何处理的。尝试各种组合,看看哪一种表现更好。请记住,随着数据集的发展,今天的“最佳”索引可能会变得不太理想。

【讨论】:

【参考方案2】:

RandomSeed 有很好的优点。但是,对于您遇到的情况,我会尝试在您所要求的最小粒度上优化索引。在这种情况下,您正在专门寻找给定的“item_ID”.. 将其移动到索引的前面位置。然后,我将有其他标准或分组作为下一个考虑因素……再次,基于结果预期的粒度。你有 Is_Category_Valid 和 Created_At.. 我希望因为大多数类别都是有效的,所以我会在第二个位置创建 created_at。这基本上是说明索引可以跳转到项目 ID 3783,并在其中转到创建日期 2013-07-07(通过 Date_sub 减少 5 天)。在这一点上,我将在 group by 索引的标准中通过,最后是 Valid

index (item_id, created_at, interval_venue_id, is_category_valid )

但是,每个查询都是不同的,您确实需要寻找最快的方法来获取粒度级别的数据......并拥有一个覆盖索引(如果可能),以防止需要进入原始页面数据级别也有助于加快速度。

【讨论】:

所以您不会将 user_id 作为索引的一部分? @gregavola,对不起,把它放在最后,因为它只是你想要的一个“额外”列,并且对于查询中的 where 或 group by / order by 条件没有任何好处。 是的,但我按该列的计数(不同的 user_id)排序。这个范围应该很高吗? @gregavola,如果您期望给定场地有很多不同的“user_id”值,那么我会在索引的“is_category_valid”部分之前有该列

以上是关于具有复杂 MySQL 查询的索引的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 索引与查询优化

具有复杂查询匹配模式的 MySQL 与 PostgreSQL 性能

具有不同的复杂 MySQL 查询

mysql索引原理与查询优化

mysql 索引

MySql存储引擎+表解压缩机制+索引+查询缓存机制+慢查询日志