【问题标题】:SQL Server 2014 execution plan creation takes a long time (fast in older versions)SQL Server 2014 执行计划创建需要很长时间(在旧版本中速度很快)
【发布时间】: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


【解决方案1】:

SQL Server 2014 有一个brand new Query Optimizer。基数估计(猜测语句将返回多少行)比过去的版本更具侵略性。存在错误和边缘情况,新优化器将花费更长的时间来找到最佳查询计划。设置较低的兼容性级别会退回到以前的查询优化器。

您的查询几乎是一种折磨测试。有更好的方法来编写它。但我认为您在新的查询优化器中暴露了一个错误。在SQL Connect 上提交错误报告。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-20
    • 2014-04-13
    相关资源
    最近更新 更多