【问题标题】:Index performance with WHERE clause in SQLSQL 中 WHERE 子句的索引性能
【发布时间】:2010-10-20 03:55:18
【问题描述】:

我正在阅读我的数据库书中的索引,我想知道我的假设是否正确:带有非常量表达式的 WHERE 子句不会使用索引。 所以如果我有

SELECT * FROM statuses WHERE app_user_id % 10 = 0;

这不会使用在 app_user_id 上创建的索引。但是

SELECT * FROM statuses WHERE app_user_id = 5;

将使用 app_user_id 上的索引。

【问题讨论】:

    标签: sql database indexing


    【解决方案1】:

    通常(还有其他选项)数据库索引是 B-Tree,这意味着您可以对其进行范围扫描(包括相等扫描)。

    条件app_user_id % 10 = 0 无法通过单次范围扫描进行评估,这就是数据库可能不使用索引的原因。

    它仍然可以决定以另一种方式使用索引,即进行全扫描:读取整个表比读取整个索引需要更多时间。另一方面,在读完索引后,您可能仍会回到表中,因此总体成本可能最终会更高。

    这由数据库查询优化器决定。

    几个例子:

     select app_user_id from t where app_user_id % 10 = 0
    

    在这里,您根本不需要表,所有必要的数据都在索引中。数据库很可能会进行全索引扫描。

     select count(*) from t where app_user_id % 10 = 0
    

    一样。全索引扫描。

     select count(*) from t
    

    只有当 app_user_id 不为 NULL 时,才能对索引执行此操作(因为 NULL 数据不在索引中,至少在 Oracle 上,至少在单列索引上,您的数据库可能会以不同方式处理此问题)。

    有些数据库不需要为此访问表或索引,它们在元数据中维护行数。

     select * from t where app_user_id = 5
    

    这是索引的经典场景。数据库可以查看索引树的一小部分,检索少量(如果这是唯一索引或主索引,则只有一个)rowid,并有选择地从表中获取这些。

     select * from t where app_user_id between 5 and 10
    

    另一个经典的索引案例。树中的范围扫描会返回少量的 rowid 以从表中获取。

     select * from t where app_user_id between 5 and 10 order by app_user_id
    

    由于索引扫描返回有序数据,您甚至可以免费获得排序。

     select * from t where app_user_id between 5 and 1000000000
    

    也许在这里您不应该使用索引。它似乎匹配了太多的记录。在这种情况下,让绑定变量隐藏数据库中的范围实际上可能是有害的。

     select * from t where app_user_id between 5 and 1000000000 
        order by app_user_id
    

    但是在这里,由于排序会非常昂贵(甚至占用临时交换磁盘空间),所以按索引顺序迭代可能是好的。也许吧。

     select * from t where app_user_id % 10 = 0
    

    这很难决定。我们需要所有列,因此最终查询需要触及表。问题是是否先通过索引。该查询返回整个表的大约 10%。这对于索引访问路径的效率来说可能太多了。如果优化器有理由相信查询返回的数据远少于表的 10%,那么在访问表之后进行索引扫描可能会很好。如果表非常碎片化(大量删除的行占用空间),则相同。

    【讨论】:

    • 所以基本上你的回答说这取决于数据库。
    • 和数据。和配置选项。此外,是否使用索引也没有关系。唯一重要的是这是否会比其他替代方案更快。无论如何,您的推理应该是“我需要运行哪些查询”,然后相应地设计架构和索引。如果您的 % 10 查询执行得不够好,您可能需要对列进行非规范化,或构建功能索引。
    猜你喜欢
    • 1970-01-01
    • 2021-11-17
    • 1970-01-01
    • 1970-01-01
    • 2014-07-17
    • 2012-07-02
    • 2017-05-27
    • 2017-02-26
    • 1970-01-01
    相关资源
    最近更新 更多