sql - 我如何优化这个查询?

标签 sql mysql optimization

我有一个非常具体的查询。我尝试了很多方法,但无法达到我想要的性能。

SELECT *
FROM
    items
WHERE
    user_id=1
AND
    (item_start < 20000 AND item_end > 30000)

我创建了 user_id、item_start、item_end 并建立了索引

这不起作用,我删除了所有索引并创建了新索引

user_id, (item_start, item_end)

这也不起作用。

(user_id、item_start 和 item_end 为整数)

编辑:数据库是MySQL 5.1.44,引擎是InnoDB

最佳答案

更新:根据您下面的评论,您需要查询中的所有列(因此您的 SELECT *)。如果是这种情况,您有几个选项可以最大限度地提高查询性能:

  1. 在 item_user_id、item_start、item_end 上创建(或更改)聚集索引。这将确保每个查询检查尽可能少的行。根据我下面的原始答案,这种方法可能会加快此特定查询的速度,但可能会减慢其他查询的速度,因此您需要小心。
  2. 如果更改聚集索引不切实际,您可以在 item_user_id、item_start、item_end 以及查询所需的任何其他列上创建非聚集索引。这会在一定程度上减慢插入速度,并使表所需的存储空间增加一倍,但会加快此特定查询的速度。

总有其他方法可以提高性能(例如,通过减少每行的大小),但主要方法是减少必须访问的行数并增加顺序访问而不是随机访问的行的百分比。上面的索引建议两者兼而有之。

原始答案如下:

在不知道确切的架构或查询计划的情况下,此查询的主要性能问题是 SELECT * 强制查找每一行的聚集索引。如果特定用户 ID 有大量匹配行,并且聚集索引的第一列不是 item_user_id,那么这将是一个非常低效的操作,因为您的磁盘将尝试从聚集索引中获取大量随机分布的行。

换句话说,尽管过滤所需的行速度很快(因为您的索引),但实际上获取数据的速度较慢。 .

但是,如果您的聚集索引按 item_user_id、item_start、item_end 排序,那么应该会加快速度。请注意,这不是万能药,因为如果您有其他依赖于不同排序的查询,或者您以不同的顺序插入行,则最终可能会减慢其他查询的速度。

一个影响较小的解决方案是创建一个覆盖索引,其中仅包含您想要的列(也按 item_user_id、item_start、item_end 排序,然后添加您需要的其他列)。然后更改您的查询以仅拉回您需要的列,而不是使用 SELECT *

如果您可以发布有关 DBMS 品牌和版本以及表架构的更多信息,我们可以提供更多详细信息。

关于sql - 我如何优化这个查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3379855/

相关文章:

sql - 连续的日期

sql - 在 if 语句中添加 delete 语句

mysql - 在 MySQL 中添加记录时插入或更新或跳过

php - 我的第一个 CakePHP 项目中未找到列错误

mysql - 我的 SQL 查询中的语法错误 : CASE error

java - java.lang.String 是否有内存高效的替代品?

sql - 尽管使用了别名,但我从内部查询中找不到列

mysql - 使用vba创建mysql数据库

Java 代码优化 - 如何优化这个 remove() 函数?

python - O(n) 寻找最大差异总和的解决方案 python 3.x?