SQL 中判断条件的先后顺序,会引起索引失效么?
在群里看到一个基础题,有关索引的使用。
题目就在这里,有的朋友说选B,有的选C,有的说题目不严谨,还有的说没答案,都是错误的。
讨论了很久,有两个共性的问题,值得拿出来说下:
- a=1 and b=1 和 b=1 and a=1 会有效利用 idx(b,a) 吗?
- b=1 还会利用索引 idx(a,b)吗?
实践出真知,我就试着上机操作下。
create database factory ;
use factory
go
create table dbo.workflow ( flowid int, flowamount int, flowcount int )
go
先回答第一个问题,判断条件的顺序会影响索引使用吗
这儿模拟题目中的 idx(b,a) 索引结构
create index idx_amt_id on dbo.workflow(flowamount,flowid)
模拟 a=1 and b=1 的查询
select * from dbo.workflow
where flowid = 1 and flowamount = 1
模拟 b=1 and a=1 的查询
select * from dbo.workflow
where flowamount = 1 and flowid = 1
可以看到,当表新建,还没有数据时,优化器根本不会去判断用不用索引,而是直接全表扫描。反正就一个数据页。
当我们加点数据时,再看看反应:
这里不得不再提下 tally table 的用法,实在看不下去利用循环来生成测试数据的方法
DECLARE @BEGIN DATETIME = '2010-01-01'
,@END DATETIME = '2017-10-30'
DECLARE @INC INT ;
SELECT @INC = DATEDIFF(DAY,@BEGIN,@END)
; WITH
L0 AS (
SELECT * FROM (VALUES(1),(2),(3)) AS T(C) )
, L1 AS (
SELECT a.C,b.C AS BC FROM L0 AS a cross join L0 AS b )
, L2 AS (
SELECT a.C,b.C AS BC FROM L1 AS a cross join L1 AS b )
, L3 AS (
SELECT a.C,b.C AS BC FROM L2 AS a cross join L2 AS b )
, L4 AS (
SELECT a.C,b.C AS BC FROM L3 AS a cross join L3 AS b )
, L5 AS (
SELECT a.C,b.C AS BC FROM L4 AS a cross join L4 AS b )
insert into dbo.workflow (flowid,flowamount,flowcount)
SELECT TOP 50000 RNK , RNK * 10, RNK + 20
FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RNK
FROM L5
) M
此时表里有5万条数据,再看上面两条查询的执行计划:
这儿模拟题目中的 idx(b,a) 索引结构
create index idx_amt_id on dbo.workflow(flowamount,flowid)
模拟 a=1 and b=1 的查询
select * from dbo.workflow
where flowid = 1 and flowamount = 1
模拟 b=1 and a=1 的查询
select * from dbo.workflow
where flowamount = 1 and flowid = 1
很明显,都会走索引 idx(b,a) 这种模式,与 b 在前和 a 在前无关。优化器可以优化这部分表达式的重组。
但,是不是所有条件表达式都没有先后顺序要求呢?肯定不是
只有在相等条件判断时,先后顺序不重要,一旦有表达式用于非等判断,顺序就很重要了,如下:
select * from dbo.workflow
where flowamount > 39 and flowid = 1
select * from dbo.workflow
where flowid = 1 and flowamount > 39
这里优化器提示(绿色字体部分),建立一个相等判断条件的索引在前,非等判断字段在后的索引 (flowid,flowamount)。所以本质上,索引结构中字段先后不受制于查询中相等判断条件表达式字段的顺序,而受制于非等条件判断表达式。即非等判断字段(flowamount>39)需要放在相等判断字段(flowid=1)的后面。
create index idx_id_amtr on dbo.workflow(flowid,flowamount)
select * from dbo.workflow
where flowamount > 39 and flowid = 1
select * from dbo.workflow
where flowid = 1 and flowamount > 39
再看两者的执行计划:
这里就走了我们刚才新建的索引 idx_id_amtr
第二个问题,b=1 还会利用索引 idx(a,b)吗?
在上面的示例中,建立 index(flowamount,flowid) 的索引,那么对应到要解决的问题,便是 where flowid = 1 会走 index(flowamount,flowid)的索引吗?
select * from dbo.workflow
where flowid = 1
由此可见 b=1 是不会利用索引 idx(a,b) 了。
注意,或许 oracle, mysql, pg, 等其他数据库会有不同,大家可以尝试实际操作下,再一起来讨论。各自优化器的算法不同,优化略微有些诧异。不必过于纠结。
- WinEdit编辑器中中文乱码
- 微信小游戏上线,2018年的H5游戏可以“跳一跳”
- QT程序在发布的时候应注意的地方
- 漂洋过海! 英文域名d.me小六位易主
- Python基础09 面向对象的进一步拓展
- QT中获取选中的radioButton的两种方法
- QT中根据ID设置radio按钮
- QWebView在 Qt 5.x中编译出错:File not found: main.obj
- Qt实现小功能之列表无限加载
- Python基础08 面向对象的基本概念
- 如何选择合适的PaaS
- 使用Qt installer framework制作安装包
- Qt Style Sheet实践(三):QCheckBox和QRadioButton
- 堆排序
- MySQL 教程
- MySQL 安装
- MySQL 管理与配置
- MySQL PHP 语法
- MySQL 连接
- MySQL 创建数据库
- MySQL 删除数据库
- MySQL 选择数据库
- MySQL 数据类型
- MySQL 创建数据表
- MySQL 删除数据表
- MySQL 插入数据
- MySQL 查询数据
- MySQL where 子句
- MySQL UPDATE 查询
- MySQL DELETE 语句
- MySQL LIKE 子句
- mysql order by
- Mysql Join的使用
- MySQL NULL 值处理
- MySQL 正则表达式
- MySQL 事务
- MySQL ALTER命令
- MySQL 索引
- MySQL 临时表
- MySQL 复制表
- 查看MySQL 元数据
- MySQL 序列 AUTO_INCREMENT
- MySQL 处理重复数据
- MySQL 及 SQL 注入
- MySQL 导出数据
- MySQL 导入数据
- MYSQL 函数大全
- MySQL Group By 实例讲解
- MySQL Max()函数实例讲解
- mysql count函数实例
- MYSQL UNION和UNION ALL实例
- MySQL IN 用法
- MySQL between and 实例讲解
- Error: Protocol error, got "H" as reply type byte
- 树莓派基础实验33:TCRT5000红外循迹传感器实验
- 10W个Java对象有多大
- 一次线程池引发的线上故障分析
- dubbo 启动Failed to save registry store file报错
- 大数据的列式存储格式:Parquet
- springBoot 入门(六)—— 整合Spring框架开启自带的任务调度器执行任务(注解方式)
- java字节流入门(缓冲输出流)
- EsotericSoftware Kryo —— 官方(1)
- Java的I/O类库的基本架构一句话介绍
- 树莓派综合项目1:智能温度测量系统实验
- 一句话ListenableFuture简介
- Google Guava Cache 使用
- Linux下安装maven3.6.2遇到的问题
- Unity3D网络通讯(五)--Socket通讯之Udp通讯