sql - SQL 中 WHERE 子句的索引性能

标签 sql database indexing

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

SELECT * FROM statuses WHERE app_user_id % 10 = 0;

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

SELECT * FROM statuses WHERE app_user_id = 5;

将使用 app_user_id 上的索引。

最佳答案

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

条件 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

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

 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%,那么在访问表之前进行索引扫描可能会比较好。如果表非常分散(大量删除的行占用空间),情况也是如此。

关于sql - SQL 中 WHERE 子句的索引性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3974653/

相关文章:

sql - 在更新语句中加密 postgres 列

MySQL - 在左连接中使用不带Where的计数

xcode - 'XCBBuildService 意外退出' Xcode 9.3 (Swift 4.1)

c - 二维数组C++指针地址

c++ - 使用整数列表文档进行全文搜索的最佳方法

sql - 如何从 PIT Azure SQL 创建 bacPac 文件

sql - 为什么即使用户登录的日期格式设置设置为 'yyyy-mm-dd',ISO 8601 日期格式 'mdy' 字符串文字仍然有效

SQL Server 约束强制执行在瞬间被违反

c++ - 如何方便快捷的存储一个大词库?

java - 在数据库中存储表达式树