SQL查询与使用Datetime列上的索引之间的区别

时间:2019-07-05 07:06:45

标签: sql sql-server tsql

我有一个简单的表,在DateTime列上有索引。

有人可以解释一下这两个查询中的哪一个使用索引吗?

CREATE TABLE exams
(
    name VARCHAR(50),
    grade INT,
    date DATETIME
);

CREATE INDEX date_idx ON exams(date);

SELECT * 
FROM exams 
WHERE date = '2018-01-01';      -- doesn't use index?

SELECT * 
FROM exams 
WHERE MONTH(date) = 1;      -- uses index?

2 个答案:

答案 0 :(得分:6)

SQL引擎有多种解决方法。让我们在表中插入一些示例数据:

DROP TABLE if exists exams;

CREATE TABLE exams(
  name varchar(50),
  grade INT,
  date datetime
);

INSERT exams
SELECT TOP (5000)  CONCAT('name', row_number() over(order by t1.number))
                   ,6
                   ,'2019-07-01'
FROM master..spt_values t1 
CROSS JOIN master..spt_values t2

INSERT exams
SELECT TOP (5)  CONCAT('name', row_number() over(order by t1.number))
                   ,6
                   ,'2019-07-02'
FROM master..spt_values t1 
CROSS JOIN master..spt_values t2

CREATE INDEX date_idx ON exams(date);

如您所见,我们已经插入:

  • 日期2019-07-01的5000行
  • 日期2019-07-02的5行

现在让我们执行以下查询:

SELECT * FROM exams WHERE date= '2019-07-01'; 

SELECT * FROM exams WHERE date= '2019-07-02'; 

SELECT * FROM exams WHERE MONTH(date)=1;

并检查执行计划:

enter image description here

在第一个查询中,引擎(由于统计信息)知道几乎所有数据都将被读取,因此它在堆上执行table scan

在第二个查询中,引擎看到将只返回很少的记录,因此不需要读取所有数据-它使用索引并执行index seek

在最后一种情况下,无法使用索引,因为查询不是sargable

因此,引擎将决定是否使用索引,以及是否执行查找或扫描。您唯一可以做的就是确保索引被覆盖,统计信息已更新且查询可保留。

答案 1 :(得分:4)

好吧,我相信事实是相反的:

第一个查询使用索引,而第二个则不。

为什么第二个查询不使用索引?因为索引列包装在防止SQL Server使用索引的函数中。

索引可以被认为是存储记录的一种方式。将函数应用于索引列可能会更改存储记录的顺序,因此使用函数时索引可能不再有效。