标签: performance-tuning

为什么添加 TOP 1 会显着降低性能?

我有一个相当简单的查询

SELECT TOP 1 dc.DOCUMENT_ID,
        dc.COPIES,
        dc.REQUESTOR,
        dc.D_ID,
        cj.FILE_NUMBER
FROM DOCUMENT_QUEUE dc
JOIN CORRESPONDENCE_JOURNAL cj
    ON dc.DOCUMENT_ID = cj.DOCUMENT_ID
WHERE dc.QUEUE_DATE <= GETDATE()
  AND dc.PRINT_LOCATION = 2
ORDER BY cj.FILE_NUMBER
Run Code Online (Sandbox Code Playgroud)

这给了我可怕的表现(就像从不费心等待它完成一样)。查询计划如下所示:

在此处输入图片说明

但是,如果我删除它,TOP 1我会得到一个看起来像这样的计划,它会在 1-2 秒内运行:

在此处输入图片说明

下面更正 PK 和索引。

TOP 1更改查询计划这一事实并不让我感到惊讶,我只是有点惊讶它使情况变得更糟。

注意:我已经阅读了这篇文章的结果并理解了 aRow Goal等的概念。我很好奇的是如何更改查询以使其使用更好的计划。目前我正在将数据转储到临时表中,然后从中取出第一行。我想知道是否有更好的方法。

编辑对于事后阅读本文的人,这里有一些额外的信息。

  • Document_Queue - PK/CI 是 D_ID,它有大约 5k 行。
  • Correspondence_Journal - PK/CI 是 FILE_NUMBER,CORRESPONDENCE_ID,它有大约 140 万行。

当我开始时,没有其他索引。我在 Correspondence_Journal (Document_Id, File_Number) 上找到了一个

performance sql-server sql-server-2008-r2 query-performance performance-tuning

41
推荐指数
4
解决办法
1万
查看次数

触发器每次都编译吗?

我们正在对 CPU 利用率高的服务器进行故障排除。在发现查询并没有真正导致它之后,我们开始研究编译。

性能监视器显示少于 50 次编译/秒和少于 15 次重新编译/秒。

在运行 XE 会话寻找编译后,我们每秒看到数千次编译。

该系统使用触发器来审计更改。大多数编译是由于触发器。触发器参考 sys.dm_tran_active_transactions。

我们的第一个想法是可能在触发器中引用 DMV 会导致它每次编译,或者可能只是这个特定的 DMV 会导致它。所以我开始测试这个理论。它每次都会编译,但我没有检查触发器是否在每次触发时编译,当它不引用 DMV 而是硬编码一个值时。每次触发时它仍在编译。删除触发器会停止编译。

  1. 我们在 XE 会话中使用 sqlserver.query_pre_execution_showplan 来跟踪编译。为什么这与 PerfMon 计数器之间存在差异?
  2. 每次触发器运行时都会收到编译事件是否正常?

复制脚本:

CREATE TABLE t1 (transaction_id int, Column2 varchar(100));
CREATE TABLE t2 (Column1 varchar(max), Column2 varchar(100));
GO

CREATE TRIGGER t2_ins
ON t2
AFTER INSERT
AS

INSERT INTO t1
SELECT (SELECT TOP 1 transaction_id FROM sys.dm_tran_active_transactions), Column2
FROM inserted;
GO

--Both of these show compilation events
INSERT INTO t2 VALUES ('row1', 'value1');
INSERT INTO …
Run Code Online (Sandbox Code Playgroud)

trigger performance sql-server performance-tuning

22
推荐指数
2
解决办法
3054
查看次数

具有快速(&lt;1 秒)读取查询性能的大型(&gt; 22 万亿项)地理空间数据集

我正在为需要快速读取查询性能的大型地理空间数据集设计一个新系统。因此,我想看看是否有人认为在以下情况下有可能或有关于合适的 DBMS、数据结构或替代方法来实现所需性能的经验/建议:

数据将从处理过的卫星雷达数据中不断产生,这些数据将覆盖全球。根据卫星分辨率和地球的陆地覆盖范围,我估计完整数据集可在全球 750 亿个离散位置产生值。在单颗卫星的整个生命周期内,输出将在每个位置产生多达 300 个值(因此总数据集超过 22 万亿个值)。这是针对一颗卫星,并且已经有第二颗在轨,未来几年计划再有两颗。所以会有很多数据!单个数据项非常简单,仅包含(经度、纬度、值),但由于项目的数量,我估计单个卫星最多可产生 100TB。

写入的数据永远不需要更新,因为它只会随着新卫星采集的处理而增长。写入性能并不重要,但读取性能至关重要。该项目的目标是能够通过一个简单的界面(例如谷歌地图上的图层)将数据可视化,其中每个点都有一个基于其平均值、梯度或某个时间随时间变化的函数的颜色值。(帖子末尾的演示)。

从这些需求来看,数据库需要具有可扩展性,我们很可能会转向云解决方案。系统需要能够处理地理空间查询,例如“附近的点(纬度,经度)”和“范围内的点(框)”,并且具有 < 1 秒的读取性能以定位单个点,以及包含多达50,000 点(尽管最好达到 200,000 点)。

到目前为止,我在 1.11 亿个位置拥有约 7.5 亿个数据项的测试数据集。我已经试用了一个 postgres/postGIS 实例,它工作正常,但没有分片的可能性,我不这样做,这将能够随着数据的增长而应付。我还试用了一个 mongoDB 实例,这似乎再次正常到目前为止,使用分片可能足以随数据量扩展。我最近了解了一些有关 elasticsearch 的知识,因此对此的任何评论都会有所帮助,因为它对我来说是新的。

这是我们想要用完整数据集实现的快速动画: Tileserver 为 7.5 亿个数据项提供可视化服务。

这个 gif(来自我的 postgres 试验)提供 (6x3) 预先计算的光栅图块,每个包含约 200,000 个点,生成每个点需要约 17 秒。通过单击一个点,通过在 < 1 秒内拉取最近位置的所有历史值来制作图表。

为长篇道歉,欢迎所有评论/建议。

performance database-design spatial performance-tuning

20
推荐指数
2
解决办法
880
查看次数

SQL Server 遇到 I/O 请求耗时超过 15 秒的情况

在生产 SQL Server 上,我们有以下配置:

3 台 Dell PowerEdge R630 服务器,合并到可用性组中
所有 3 台都连接到作为 RAID 阵列的单个戴尔 SAN 存储单元

有时,在 PRIMARY 上,我们会看到类似于以下内容的消息:

SQL Server 在数据库 ID 8 中
的文件 [F:\Data\MyDatabase.mdf] 上遇到了 11 次 I/O 请求需要超过 15 秒才能完成。操作系统文件句柄为 0x0000000000001FBC。
最近一次 long I/O 的偏移量为:0x000004295d0000。
长 I/O 的持续时间为:37397 毫秒。

我们是性能故障排除的新手

解决此与存储相关的特定问题的最常见方法或最佳实践是什么?

必须使用哪些性能计数器、工具、监视器、应用程序等来缩小此类消息的根本原因?

可能有一个扩展事件可以提供帮助,或者某种审计/日志记录?

更新:添加了我自己的答案(见下文),解释了我们为解决问题所做的工作

performance storage sql-server-2017 performance-tuning

20
推荐指数
4
解决办法
2万
查看次数

标识列上的索引应该是非聚集的吗?

对于具有标识列的表,是否应该为标识列创建聚集或非聚集 PK/唯一索引?

原因是将为查询创建其他索引。使用非聚集索引(在堆上)并返回索引未涵盖的列的查询将使用较少的逻辑 I/O (LIO),因为没有额外的聚集索引 b 树查找步骤?

create table T (
  Id int identity(1,1) primary key, -- clustered or non-clustered? (surrogate key, may be used to join another table)
  A .... -- A, B, C have mixed data type of int, date, varchar, float, money, ....
  B ....
  C ....
  ....)

create index ix_A on T (A)
create index ix_..... -- Many indexes can be created for queries

-- Common query is query on A, B, C, ....
select A, …
Run Code Online (Sandbox Code Playgroud)

performance sql-server database-internals index-tuning heap performance-tuning

19
推荐指数
3
解决办法
5821
查看次数

更改数据库默认排序规则时 Latin1_General_BIN 性能影响

我已将数据库排序规则设置为Latin1_General_BIN, 以使字符串比较区分大小写。这会影响性能吗?对数据库中的 DML 或 DDL 操作有什么影响吗?数据库已存在,其中包含表。

performance sql-server collation sql-server-2008-r2 unicode performance-tuning

18
推荐指数
2
解决办法
3万
查看次数

'SELECT TOP' 性能问题

我有一个查询,它使用 select 运行得更快,top 100而不使用top 100. 返回的记录数为 0。你能解释一下查询计划的差异或分享解释这种差异的链接吗?

没有top文本的查询:

SELECT --TOP 100
*
FROM InventTrans
     JOIN
     InventDim
     ON InventDim.DATAAREAID = 'dat' AND 
        InventDim.INVENTDIMID = InventTrans.INVENTDIMID
WHERE InventTrans.DATAAREAID = 'dat' AND 
      InventTrans.ITEMID = '027743' AND 
      InventDim.INVENTLOCATIONID = '???? ?????' AND 
      InventDim.ECC_BUSINESSUNITID = '?????????';
Run Code Online (Sandbox Code Playgroud)

上面的查询计划(没有top):

https://pastebin.com/cbtJpxFf

在此处输入图片说明

IO 和 TIME 统计信息(没有top):

SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = …
Run Code Online (Sandbox Code Playgroud)

performance sql-server t-sql query-performance performance-tuning

18
推荐指数
2
解决办法
4978
查看次数

关于查询计划中内存“过度授予”的警告 - 如何找出导致它的原因?

我正在运行一个查询,该查询给出有关内存的警告Excessive Grant

使用的表和索引太多,包括复杂的view,因此很难在此处添加所有定义。

我试图找出我可能导致Excessive Grant. 可以转换吗?

查看执行计划,我可以看到以下内容:

<ScalarOperator
  ScalarString="CONVERT(date,[apia_repl_sub].[dbo].[repl_Aupair].[ArrivalDate] as [repl].[ArrivalDate],0)">
  <Convert DataType="date" Style="0" Implicit="false">
    <ScalarOperator>
      <Identifier>
        <ColumnReference Database="[apia_repl_sub]" Schema="[dbo]" Table="[repl_Aupair]" Alias="[repl]" Column="ArrivalDate" />
      </Identifier>
    </ScalarOperator>
  </Convert>
</ScalarOperator>
Run Code Online (Sandbox Code Playgroud)

和这个:

<ScalarOperator ScalarString="CONVERT(date,[JUNOCORE].[dbo].[applicationPlacementInfo].[arrivalDate] as [pi].[arrivalDate],0)">
  <Convert DataType="date" Style="0" Implicit="false">
    <ScalarOperator>
      <Identifier>
        <ColumnReference Database="[JUNOCORE]" Schema="[dbo]" Table="[applicationPlacementInfo]" Alias="[pi]" Column="arrivalDate" />
      </Identifier>
    </ScalarOperator>
  </Convert>
</ScalarOperator>
Run Code Online (Sandbox Code Playgroud)

这是查询,尽管您也可以在此处查看带有执行计划的查询

DECLARE @arrivalDate DATEtime = '2018-08-20'

SELECT      app.applicantID,
            app.applicationID,
            a.preferredName,
            u.firstname,
            u.lastname,
            u.loginId                       AS emailAddress,
            s.status                        AS statusDescription,
            CAST(repl.arrivalDate AS DATE)  AS …
Run Code Online (Sandbox Code Playgroud)

performance sql-server optimization execution-plan query-performance performance-tuning

18
推荐指数
1
解决办法
2万
查看次数

当我添加连接提示时,为什么 SQL Server 行估计会发生变化?

我有一个查询,它连接了几个表并且执行得非常糟糕 - 行估计偏离了(1000 次)并且选择了嵌套循环连接,从而导致多个表扫描。查询的形状相当简单,看起来像这样:

SELECT t1.id
FROM t1
INNER JOIN t2 ON t1.id = t2.t1_id
LEFT OUTER JOIN t3 ON t2.id = t3.t2_id
LEFT OUTER JOIN t4 ON t3.t4_id = t4.id 
WHERE t4.id = some_GUID
Run Code Online (Sandbox Code Playgroud)

玩弄查询时,我注意到当我提示它对其中一个连接使用合并连接时,它的运行速度要快很多倍。这我可以理解 - 合并连接是连接数据的更好选择,但 SQL Server 只是没有正确选择嵌套循环。

我不完全理解的是为什么这个连接提示会改变所有计划运营商的所有估计?通过阅读不同的文章和书籍,我假设基数估计是在构建计划之前执行的,因此使用提示不会改变估计,而是明确告诉 SQL Server 使用特定的物理连接实现。

然而,我看到的是合并提示使所有估计变得非常完美。为什么会发生这种情况,是否有任何通用技术可以使查询优化器在没有提示的情况下做出更好的估计 - 考虑到统计数据显然允许这样做?

UPD:匿名执行计划可以在这里找到:https ://www.dropbox.com/s/hchfuru35qqj89s/merge_join.sqlplan?dl =0 https://www.dropbox.com/s/38sjtv0t7vjjfdp/no_hints_join.sqlplan?dl =0

我使用 TF 3604、9292 和 9204 检查了这两个查询使用的统计数据,它们是相同的。然而,被扫描/搜索的索引在查询之间是不同的。

除此之外,我尝试运行查询OPTION (FORCE ORDER)- 它比使用合并联接运行得更快,为每个联接选择 HASH MATCH。

performance sql-server optimization t-sql performance-tuning

16
推荐指数
1
解决办法
584
查看次数

如何跟踪发生不到一秒的阻塞 - SQL Server

我正在尝试解决发生不到一秒钟的阻塞问题。OLTP 应用程序非常敏感,根据商定的 SLA,某些事务的响应时间必须小于 200 毫秒。我们在新代码版本中遇到了一些锁升级问题,我们能够通过减少更新中的批量大小来解决这些问题。即使批量较小,我们也怀疑新的 sp 阻塞了 OLTP 事务正在更新的相同行。

我需要找到被阻塞的会话及其等待的资源。根据我的理解,“阻塞进程阈值”可以设置至少 1 秒,因此这不会捕获阻塞。

我正在试验 wait_info 和 wait_completed x 事件。

有没有其他方法可以跟踪这个。谢谢

performance sql-server sql-server-2014 query-performance performance-tuning

14
推荐指数
2
解决办法
1018
查看次数