【发布时间】:2014-11-28 10:12:36
【问题描述】:
我在 SQL Server 2014 中遇到了一个查询问题。第一次运行此查询时,生成执行计划需要很长时间。
奇怪的是,它在所有以前的 SQL Server 版本(2012、2008 R2、2008 等)中都运行良好。 它似乎与其中一个涉及的表上的唯一索引有关,并结合了主查询中的一定数量的子查询。
这是查询中涉及的表。与原始表格相比,我已经简化了很多表格,但问题仍然存在。请注意 table2 上的唯一约束,这似乎是导致问题的原因。不管是唯一约束、唯一索引,甚至是Table2上的主键,结果都是一样的。
IF OBJECT_ID('Table2') IS NOT NULL DROP TABLE [Table2]
IF OBJECT_ID('Table1') IS NOT NULL DROP TABLE [Table1]
CREATE TABLE [dbo].[Table1] ( [ReferencedColumn] [int] NOT NULL PRIMARY KEY)
CREATE TABLE [dbo].[Table2] ( [ReferencedColumn] [int] NOT NULL FOREIGN KEY REFERENCES [Table1] ([ReferencedColumn]), [IntColumn] [int] NOT NULL, [AnotherIntColumn] [int] NULL )
CREATE UNIQUE NONCLUSTERED INDEX [IX_Table2] ON [dbo].[Table2] ([ReferencedColumn], [IntColumn])
如果我随后使用 select 语句中的索引从表中执行一些子查询,则第一次完成需要很长时间(在我的测试中超过 30 秒)。
SELECT (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 1 ),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 2 ),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 3 ),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 4 ),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 5 ),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 6 ),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 7 ),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 8 ),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 9 ),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 10),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 11),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 12),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 13),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 14),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 15),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 16),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 17),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 18),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 19),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 20),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 21),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 22),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 23),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 24),
(SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 25)
FROM Table1 F
由于表中没有行,而且查询在第一次运行后立即运行,所以在我看来,它必须是需要很长时间才能生成的执行计划。
但是,如果您执行下列更改之一,则会立即生成执行计划。
- 删除索引
- 删除索引的唯一部分
- 将 AnotherIntColumn 添加到索引中
- 将数据库的兼容级别设置为 SQL Server 2012
值得注意的是,生成的执行计划在各个版本中是相同的,只是生成的时间有所不同。该计划包括许多“计算标量”操作,但我看不出有什么问题,因为在 2012/2008 年立即生成相同的计划。
我只在 SQL Server 2014 Enterprise 和 Web 版本的几个实例上对其进行了测试,但我认为在 2014 的其他版本上也会发生相同的行为。
我已经有几种解决问题的方法(修改索引、更改兼容级别、重写查询),但我很好奇为什么与旧版本的 SQL Server 相比性能下降如此之大?
【问题讨论】:
-
第一次运行时,没有缓存查询计划,因此 SQL Server 做更多的工作来执行计算/估计。第一次运行后,它使用第一次运行后生成的缓存计划,因此速度更快。
-
我明白这一点,但为什么在 SQL Server 2014 上需要这么长时间?只有在这个版本的 SQL Server 中第一次需要很长时间,在旧版本中不会。
标签: sql-server tsql sql-server-2014