AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 264128
Accepted
QFirstLast
QFirstLast
Asked: 2020-04-03 00:07:27 +0800 CST2020-04-03 00:07:27 +0800 CST 2020-04-03 00:07:27 +0800 CST

为什么一个简单的查询在 MS SQL Server 2014 或 2014SP3 上的性能很差,而在其他版本上却表现良好?

  • 772

我在 MS SQL Server 2014(以及 2014SP3)上运行以下查询

SET NOCOUNT ON

CREATE TABLE #GUIDs(
  PartyNames_GUID  UNIQUEIDENTIFIER NULL,
  Party_GUID UNIQUEIDENTIFIER  NULL,
  FirstName  NVARCHAR(255)  NULL
)

insert #GUIDs(Party_GUID)
select top 1 Party_GUID 
FROM Party a 
join PartyNames b on a.Party_ID = b.Party_ID 

--Give the optimizer all kinds of choices. 
create  index i1 on #GUIDs(PartyNames_GUID)
create  index i2 on #GUIDs(Party_GUID)
create  index i3 on #GUIDs(Party_GUID, PartyNames_GUID)
create  index i4 on #GUIDs(PartyNames_GUID,Party_GUID)
update statistics #GUIDs


SELECT  PartyNames.PartyNames_ID,       PartyNames.LastName,        PartyNames.FirstName
FROM Party  INNER JOIN PartyNames   ON PartyNames.Party_ID = Party.Party_ID  
            INNER JOIN #GUIDs       ON Party.Party_GUID = #GUIDs.Party_GUID                     --Hard Match on Party_GUID
                                                     AND 
      (#GUIDs.PartyNames_GUID IS NULL OR PartyNames.PartyNames_GUID = #GUIDs.PartyNames_GUID )  --Optional Match
                                                    AND 
            (#GUIDs.FirstName IS NULL OR PartyNames.FirstName = #GUIDs.FirstName )          --Optional Match

drop table #GUIDs

Party 和 PartyNames 表在它们的主 _ID 上都有一个聚集索引,在它们各自的 GUID 上有一个非聚集唯一索引,而 PartyNames 在来自 Party 的外键上有一个索引。这些表的 DDL 包含在末尾,以免混淆问题的描述。Party 有大约 1.9M 行,PartyNames 有 1.3M。PartyNames 每个 Party 最多可以有 3 条记录。上面的查询需要几百毫秒才能运行。但相同的查询在 SQL Server 2012、2016 和 2019 上运行时间为 15 毫秒或更短。所有版本的架构都相同,完全相同的数据在 BCP 完成后和运行查询之前更新。这是 2014 年执行计划的外观 在此处输入图像描述 这是其他 SQL Server 版本的执行计划,2012、2016、2019 在此处输入图像描述

为什么 2014 年会产生如此糟糕的计划,它扫描 PartyNames 的主键而不是寻找
[PartyNames].[ix_PartyNames_Party_ID?或者更确切地说,高于和低于 2014 的版本如何设法提出一个好的计划,而 2014 没有?其他版本生成的计划显然更好,因为它消耗更少的 CPU 和更少的 IO。是 2014 年的某些服务器设置导致了这种情况吗?SQL Server 2014 优化器的成本计算与之前或之后的版本有很大不同吗?任何帮助或指针表示赞赏。我不愿意认为这是 SQL Server 2014 中的一个缺点。有趣的是,即使记录数减少到几千条,SQL Server 2014 仍会继续生成相同的错误计划。但是删除最后一个 AND 子句 (#GUIDs.FirstName IS NULL OR PartyNames.FirstName = #GUIDs.FirstName ) 会导致 SQL Server 2014 生成与其他版本相同的良好计划。这当然是人为的复制。在 MS SQL Server 2014 上运行我们产品的客户抱怨性能不佳,而在其他版本上则没有。对问题进行故障排除会导致这种简单的再现。

这是用于模式生成的 DDL

CREATE TABLE [dbo].[Party](
    [Party_ID] [int] IDENTITY(1,1) NOT NULL,
    [Party_GUID] [uniqueidentifier] ROWGUIDCOL  NOT NULL,
 CONSTRAINT [pk_Party_Party_ID] PRIMARY KEY CLUSTERED ( [Party_ID] ASC),
 CONSTRAINT [uq_Party_Party_GUID] UNIQUE NONCLUSTERED ( [Party_GUID] ASC)
) 
GO
ALTER TABLE [dbo].[Party] ADD  CONSTRAINT [df_Party_Party_GUID]  DEFAULT (newid()) FOR [Party_GUID]
GO




CREATE TABLE [dbo].[PartyNames](
    [PartyNames_ID] [int] IDENTITY(1,1) NOT NULL,
    [PartyNames_GUID] [uniqueidentifier] ROWGUIDCOL  NOT NULL,
    [Party_ID] [int] NOT NULL,
    [FirstName] [nvarchar](255) NULL,
    [MiddleName] [nvarchar](255) NULL,
    [LastName] [nvarchar](255) NULL,
 CONSTRAINT [pk_PartyNames_PartyNames_ID] PRIMARY KEY CLUSTERED ([PartyNames_ID] ASC),
 CONSTRAINT [uq_PartyNames_PartyNames_GUID] UNIQUE NONCLUSTERED ([PartyNames_GUID] ASC)
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[PartyNames] ADD  CONSTRAINT [df_PartyNames_PartyNames_GUID]  DEFAULT (newid()) FOR [PartyNames_GUID]
GO

ALTER TABLE [dbo].[PartyNames]  WITH NOCHECK ADD  CONSTRAINT [fk_PartyNames_Party_ID] FOREIGN KEY([Party_ID])
REFERENCES [dbo].[Party] ([Party_ID])
GO

ALTER TABLE [dbo].[PartyNames] CHECK CONSTRAINT [fk_PartyNames_Party_ID]
GO
CREATE NONCLUSTERED INDEX [ix_PartyNames_Party_ID] ON [dbo].[PartyNames]
(
    [Party_ID] ASC
)
GO
performance sql-server-2014
  • 1 1 个回答
  • 93 Views

1 个回答

  • Voted
  1. Best Answer
    Josh Darnell
    2020-04-03T04:07:04+08:002020-04-03T04:07:04+08:00

    您需要启用记录和支持的跟踪标志 4199(启用查询优化器修复)来纠正此问题。

    您可以在查询级别启用它来测试它,但这需要系统管理员权限(希望您的应用程序没有)。可以提出一个非常有说服力的论点来全局打开它(作为启动跟踪标志),您可以在此处阅读一些讨论:跟踪标志 4199 - 全局启用?


    我能够使用以下测试数据重现您的问题:

    INSERT INTO dbo.Party
        (Party_GUID)
    SELECT TOP (1900000)
        NEWID()
    FROM master.dbo.spt_values v1
    CROSS JOIN master.dbo.spt_values v2;
    
    INSERT INTO dbo.PartyNames
        (Party_ID, PartyNames_GUID)
    SELECT TOP (1300000)
        Party_ID,
        NEWID()
    FROM dbo.Party;
    

    获取测试查询的估计计划会产生错误的计划:

    糟糕计划的截图

    优化器选择扫描聚簇索引,dbo.PartyNames因为出于某种原因,它认为其中的每一行都dbo.PartyNames将与从中检索的一行匹配dbo.Party。

    添加OPTION (QUERYTRACEON 4199)到查询的末尾可以纠正这个错误的推理并产生好的计划:

    好计划的截图

    有关 TF 4199 的详细信息,请参阅此 KB:SQL Server 查询优化器修补程序跟踪标志 4199 服务模型


    另一种解决方案是使用带有跟踪标志 9481 的遗留基数估计器,这也产生了良好的计划。

    • 2

相关问题

  • 使用存储过程处理数据与在检索后将其输入函数相比是否有性能提升?

  • 您如何针对繁重的 InnoDB 工作负载调整 MySQL?

  • 如何确定是否需要或需要索引

  • 我在哪里可以找到mysql慢日志?

  • 如何优化大型数据库的 mysqldump?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve