我如何优化此查询?

时间:2010-07-31 21:28:45

标签: 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是int)

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

2 个答案:

答案 0 :(得分:2)

更新:根据您的评论,您需要查询中的所有列(因此您的SELECT *)。如果是这种情况,您可以使用一些选项来最大化查询性能:

  1. 创建(或更改)您的聚集索引,使其位于item_user_id,item_start,item_end上。这将确保为每个查询检查尽可能少的行。根据我在下面的原始答案,这种方法可能会加速这个特定的查询,但可能会减慢其他查询,所以你需要小心。
  2. 如果更改聚簇索引不切实际,可以在item_user_id,item_start,item_end和查询所需的任何其他列上创建非聚集索引。这会稍微减慢插入速度,并且会使您的表所需的存储空间加倍,但会加快此特定查询的速度。
  3. 总有其他方法可以提高性能(例如,通过减少每行的大小),但主要方法是减少必须访问的行数,并增加按顺序访问而不是随机访问的行的百分比。上面的索引建议同时做到了。

    下面的原始答案:

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

    换句话说,即使过滤所需的行也很快(因为你的索引),实际上获取数据的速度较慢。

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

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

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

答案 1 :(得分:1)

你需要SELECT *吗? 如果没有,您可以在user_id,item_start,item_end上创建索引,并在SELECT-part中将所需字段作为包含列。这一切都假设您正在使用Microsoft SQL Server 2005 +