标签: query-performance

在 T-SQL 中使用 IF 会削弱或破坏执行计划缓存吗?

有人向我建议,在 t-SQL 批处理中使用 IF 语句对性能有害。我试图找到一些确认或验证这个断言。我使用的是 SQL Server 2005 和 2008。

断言是以下批次:-

IF @parameter = 0
 BEGIN
  SELECT ... something
 END

ELSE
 BEGIN
  SELECT ... something else
 END
Run Code Online (Sandbox Code Playgroud)

SQL Server 无法重用生成的执行计划,因为下一次执行可能需要不同的分支。这意味着 SQL Server 将从执行计划中完全删除一个分支,因为它已经可以确定当前执行需要哪个分支。这是真的吗?

此外,在这种情况下会发生什么:-

IF EXISTS (SELECT ....)
 BEGIN
  SELECT ... something
 END

ELSE
 BEGIN
  SELECT ... something else
 END
Run Code Online (Sandbox Code Playgroud)

无法提前确定将执行哪个分支?

performance sql-server-2005 sql-server-2008 sql-server query-performance

20
推荐指数
3
解决办法
7422
查看次数

根据我正在更新的行数,使用完全不同的计划的 T-SQL 查询

我有一个带有“TOP (X)”子句的 SQL UPDATE 语句,我正在更新值的行大约有 40 亿行。当我使用“TOP (10)”时,我得到一个几乎立即执行的执行计划,但是当我使用“TOP (50)”或更大时,查询永远不会(至少,在我等待时不会)完成,并且它使用完全不同的执行计划。较小的查询使用带有一对索引查找和嵌套循环连接的非常简单的计划,其中完全相同的查询(在 UPDATE 语句的 TOP 子句中具有不同的行数)使用涉及两个不同索引查找的计划、表线轴、并行性和一堆其他复杂性。

我使用了“OPTION (USE PLAN...)”来强制它使用由较小查询生成的执行计划——当我这样做时,我可以在几秒钟内更新多达 100,000 行。我知道查询计划很好,但 SQL Server 只会在只涉及少量行时自行选择该计划 - 我的更新中任何相当大的行数都会导致次优计划。

我认为并行性可能是罪魁祸首,所以我设置MAXDOP 1了查询,但没有效果 - 这一步已经消失,但糟糕的选择/性能没有。我sp_updatestats今天早上也跑了,以确保这不是原因。

我附上了两个执行计划 - 越短的执行计划也越快。此外,这里是有问题的查询(值得注意的是,我包含的 SELECT 在小行数和大行数的情况下似乎都很快):

    update top (10000) FactSubscriberUsage3
               set AccountID = sma.CustomerID
    --select top 50 f.AccountID, sma.CustomerID
      from FactSubscriberUsage3 f
      join dimTime t
        on f.TimeID = t.TimeID
      join #mac sma
        on f.macid = sma.macid
       and t.TimeValue between sma.StartDate and sma.enddate 
     where f.AccountID = 0 --There's a filtered index …
Run Code Online (Sandbox Code Playgroud)

performance sql-server execution-plan query-performance

20
推荐指数
1
解决办法
2410
查看次数

强迫流不同

我有一张这样的表:

CREATE TABLE Updates
(
    UpdateId INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
    ObjectId INT NOT NULL
)
Run Code Online (Sandbox Code Playgroud)

本质上是跟踪 ID 增加的对象的更新。

该表的使用者将选择一个由 100 个不同对象 ID 组成的块,按UpdateId特定的UpdateId. 本质上,跟踪它停止的位置,然后查询任何更新。

我发现这是一个有趣的优化问题,因为我只能通过编写由于索引而碰巧做我想要的查询来生成最大优化的查询计划,但不保证我想要什么:

SELECT DISTINCT TOP 100 ObjectId
FROM Updates
WHERE UpdateId > @fromUpdateId
Run Code Online (Sandbox Code Playgroud)

@fromUpdateId存储过程参数在哪里。

有以下计划:

SELECT <- TOP <- Hash match (flow distinct, 100 rows touched) <- Index seek
Run Code Online (Sandbox Code Playgroud)

由于UpdateId正在使用索引上的搜索,结果已经很好,并且按照我想要的从最低到最高的更新 ID 排序。这会生成一个流程不同的计划,这就是我想要的。但是排序显然不能保证行为,所以我不想使用它。

这个技巧也会产生相同的查询计划(尽管有一个冗余的 TOP):

WITH ids AS
(
    SELECT ObjectId
    FROM Updates …
Run Code Online (Sandbox Code Playgroud)

performance sql-server optimization sql-server-2014 query-performance

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

为什么在 SQL Server 中“select *”比“select top 500 *”快?

我有一个观点,complicated_view-- 有一些连接和 where 子句。现在,

select * from complicated_view (9000 records)
Run Code Online (Sandbox Code Playgroud)

更快,更快,比

select top 500 * from complicated_view
Run Code Online (Sandbox Code Playgroud)

我们说的是 19 秒对 5+ 分钟。

第一个查询返回所有 9000 条记录。如何只获得前 500 名的时间长得可笑?

显然,我将在这里查看执行计划 ---- 但是一旦我弄清楚为什么SQL Server 以次优方式运行“前 500”,我该如何实际告诉它以快速方式运行计划,喜欢坐满桌?

当然,我可能不得不完全重写视图——但很奇怪。

基本上,我将此数据表连接到第 3 方软件,该软件使用select top 500 *无法修改的默认查询预先检查表。因此,除了将此视图转储到实际表中(非常草率)之外,我也无法绕过他们的“前 500 名”附录。

这是 SQL Server 2012。

编辑:不同意重复标志。另一个问题,顶部比所有的都快。这将是预期的行为,返回较少的行。我的情况正好相反。另外,我的理解是 Top 100 是一种与 Top 100+ 不同的算法。我什至不认为重复的问题有正确的答案。也就是说,TOP X 查询将在很早的时候对潜在的大量表进行排序,而不是在它们被聚合/过滤/等之后。为什么是一个谜,但如何显然存在。

performance sql-server execution-plan select top query-performance

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

检索日期范围的最有效方法

使用这样的表结构检索日期范围的最有效方法是什么?

create table SomeDateTable
(
    id int identity(1, 1) not null,
    StartDate datetime not null,
    EndDate datetime not null
)
go
Run Code Online (Sandbox Code Playgroud)

假设你想要既范围StartDateEndDate。因此,换句话说,如果StartDate介于@StartDateBeginand之间@StartDateEnd,并且EndDate介于@EndDateBeginand之间@EndDateEnd,则执行某些操作。

我知道有几种方法可以解决这个问题,但最建议的是什么?

performance sql-server query-performance

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

索引对更新列不在索引中的更新语句的影响

我经常看到人们说索引变慢了updatedelete并且insert。这被用作笼统的陈述,就好像它是绝对的一样。

在调整我的数据库以提高性能的同时,我不断遇到这种情况,这对我来说在逻辑上似乎与该规则相矛盾,而且我找不到任何人以其他方式说或解释。

在 SQL Server 中,我相信/假定大多数其他 DBMS,您的索引是根据您指定的特定列创建的。插入和删除总是会影响整行,因此它们不可能不影响索引,但更新似乎更独特一些,它们只能专门影响某些列。

如果我有未包含在任何索引中的列并且我更新它们,它们是否会因为我在该表中的其他列上有索引而变慢?

例如,在我的User表中,我有一个或两个索引,主键是 Identity/Auto Increment 列,另一个可能是某个外键列。
如果我直接更新一个没有索引的列,比如他们的电话号码或地址,这个更新是否会变慢,因为我在这两种情况下的其他列上都有索引?我正在更新的列不在索引中,所以从逻辑上讲,索引不应该更新,不是吗?如果有的话,我认为如果我在 WHERE 子句中使用索引,它们会加速。

performance index sql-server update query-performance

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

SQL Server--如果存储过程和计划缓存中的逻辑

SQL Server 2012 和 2016 标准:

如果我将if-else逻辑放在存储过程中以执行代码的两个分支之一,取决于参数的值,引擎是否缓存最新版本?

如果在接下来的执行中,参数的值发生了变化,它是否会重新编译并重新缓存存储过程,因为必须执行代码的不同分支?(此查询的编译成本非常高。)

performance sql-server sql-server-2016 query-performance

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

'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万
查看次数

单行 INSERT...SELECT 比单独的 SELECT 慢得多

给定以下堆表,其中包含 400 行,编号从 1 到 400:

DROP TABLE IF EXISTS dbo.N;
GO
SELECT 
    SV.number
INTO dbo.N 
FROM master.dbo.spt_values AS SV
WHERE 
    SV.[type] = N'P'
    AND SV.number BETWEEN 1 AND 400;
Run Code Online (Sandbox Code Playgroud)

以及以下设置:

SET NOCOUNT ON;
SET STATISTICS IO, TIME OFF;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
Run Code Online (Sandbox Code Playgroud)

以下SELECT语句在大约6 秒内完成(demoplan):

DECLARE @n integer = 400;

SELECT
    c = COUNT_BIG(*) 
FROM dbo.N AS N
CROSS JOIN dbo.N AS N2
CROSS JOIN dbo.N …
Run Code Online (Sandbox Code Playgroud)

performance sql-server insert execution-plan query-performance

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