标签: execution-plan

存储顺序与结果顺序

这是主键中指定的排序顺序的衍生问题,但排序是在 SELECT 上执行的

@Catcall关于存储顺序(聚集索引)和输出顺序的主题

很多人认为聚集索引可以保证输出的排序顺序。但这不是它的作用。它保证了磁盘上的存储顺序。 例如,请参阅此博客文章

我已经阅读了 Hugo Kornelis 的博客文章,并了解到索引并不能保证 sql server 以特定顺序读取记录。然而,我很难接受我不能为我的场景假设这一点?

CREATE TABLE [dbo].[SensorValues](
  [DeviceId] [int] NOT NULL,
  [SensorId] [int] NOT NULL,
  [SensorValue] [int] NOT NULL,
  [Date] [int] NOT NULL,
CONSTRAINT [PK_SensorValues] PRIMARY KEY CLUSTERED 
(
  [DeviceId] ASC,
  [SensorId] ASC,
  [Date] DESC
) WITH (
    FILLFACTOR=75,
    DATA_COMPRESSION = PAGE,
    PAD_INDEX = OFF,
    STATISTICS_NORECOMPUTE = OFF,
    SORT_IN_TEMPDB = OFF,
    IGNORE_DUP_KEY = OFF,
    ONLINE = OFF,
    ALLOW_ROW_LOCKS = ON,
    ALLOW_PAGE_LOCKS = ON)
  ON …
Run Code Online (Sandbox Code Playgroud)

sql-server clustered-index execution-plan sorting

8
推荐指数
1
解决办法
4773
查看次数

如果参数存储在局部变量中,则更好的执行计划

我有两个存储过程。这个速度非常快(约 2 秒)

CREATE PROCEDURE [schema].[Test_fast]
   @week date
AS
BEGIN

    declare @myweek date = @week

    select distinct serial 
    from [schema].[tEventlog]         as e
    join [schema].tEventlogSourceName as s on s.ID = e.FKSourceName
    where s.SourceName = 'source_name'
        and (e.EventCode = 1 or e.EventCode = 9)
        and cast(@myweek as datetime2(3)) <= [Date] 
        and [Date] < dateadd(day, 7, cast(@myweek as datetime2(3)))    
END
Run Code Online (Sandbox Code Playgroud)

而这个运行缓慢(~ 2 小时):

create PROCEDURE [schema].[Test_slow]
   @week date
AS
BEGIN

    select distinct serial 
    from [schema].[tEventlog]         as e
    join [schema].tEventlogSourceName as s on s.ID …
Run Code Online (Sandbox Code Playgroud)

performance sql-server stored-procedures execution-plan parameter query-performance

8
推荐指数
1
解决办法
3609
查看次数

为嵌套循环设置统计 I/O

考虑以下查询:

CREATE PROC dbo.GetPage  @orderid  AS INT    = 0, -- anchor sort key
            @pagesize AS BIGINT = 25
 AS
SELECT
TOP (@pagesize) orderid, orderdate, custid, empid
 FROM dbo.Orders WHERE orderid > @orderid ORDER BY orderid;

exec GetPage 25,25
Run Code Online (Sandbox Code Playgroud)

上述查询的 SET STATISTICS IO 返回:

(25 row(s) affected)
Table 'Orders'. Scan count 1, logical reads 87, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Run Code Online (Sandbox Code Playgroud)

Itzik Ben-Gan 在他的书中对上述内容的解释是这样的:

执行查询计划所涉及的 I/O 成本由以下组成:

  • 查找索引的叶子:3 次读取(索引具有三个级别)。 …

sql-server execution-plan database-internals sql-server-2016

8
推荐指数
1
解决办法
950
查看次数

临时表上的索引使用情况

我有两个相当简单的查询。第一个查询

 UPDATE mp_physical SET periodic_number = '' WHERE periodic_number is NULL;
Run Code Online (Sandbox Code Playgroud)

这是计划

 duration: 0.125 ms  plan:
    Query Text: UPDATE mp_physical  SET periodic_number = '' WHERE periodic_number is NULL;
    Update on mp_physical  (cost=0.42..7.34 rows=1 width=801)
      ->  Index Scan using "_I_periodic_number" on mp_physical  (cost=0.42..7.34 rows=1 width=801)
            Index Cond: (periodic_number IS NULL)
Run Code Online (Sandbox Code Playgroud)

第二个:

 UPDATE observations_optical_temp SET designation = '' WHERE periodic_number is NULL;
Run Code Online (Sandbox Code Playgroud)

它的计划是:

duration: 2817.375 ms  plan:
    Query Text: UPDATE observations_optical_temp SET periodic_number = '' WHERE periodic_number is NULL;
    Update on observations_optical_temp …
Run Code Online (Sandbox Code Playgroud)

postgresql performance index execution-plan temporary-tables postgresql-performance

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

查询内存授予和 tempdb 溢出

我有一个长时间运行的查询(有 1 亿行的事实表加入了一些小的暗表然后分组),它溢出到 tempdb,即使(经过一些调整)CE 非常接近实际的行数,请参阅计划:

在此处输入图片说明

寻找解释,我注意到以下内存授予信息:

在此处输入图片说明

环境:SQL Server 2012 SP1 Enterprise,服务器 RAM 256 GB,SQL Server 最大内存 200 GB,缓冲池大小 42 GB,工作区最大大小 156 GB(GrantedMemory = 156 * 25% ~= 38 GB)

问题

  1. 这是否意味着无论 CE 有多好,查询都没有机会不溢出?因为查询最大 ram 的上限为 38 GB
  2. 查询优化器在构建计划时是否不考虑最大查询内存?(强制哈希匹配聚合将消除排序步骤并显着提高查询性能,不幸的是,实际查询来自 Cognos,我们无法控制它)
  3. 将 25% 的上限增加到接近 100% 是一个明智的选择吗?(假设可以控制所述服务器访问以限制并发查询请求的数量)

Paste The Plan 上的匿名查询计划

强制哈希匹配聚合(而不是排序 + 流聚合)时,查询始终快 3 - 4 倍。不幸的是,实际查询来自 Cognos,我们无法更改它。

散列聚合计划中没有散列溢出。查询优化器不会选择散列匹配聚合,因为如果我查看散列与流聚合的运算符成本,散列组的 CPU 成本比进行流聚合高 2 - 3 倍。

在流和哈希聚合中,估计的输出行与输入(约 1 亿行)完全相同。

查询使用单个 NC 列存储索引,并且列统计信息都定期更新。

sql-server execution-plan sql-server-2012 tempdb sorting

8
推荐指数
2
解决办法
2700
查看次数

为什么在 BIGINT col 上的此查找具有额外的常量扫描、计算标量和嵌套循环运算符?

当我查看一些查询的实际执行计划时,我注意到 WHERE 子句中使用的文字常量显示为计算标量常量 scan的嵌套链。

sql工作室截图

为了重现这一点,我使用下表

CREATE TABLE Table1 (
    [col1] [bigint] NOT NULL,
    [col2] [varchar](50) NULL,
    [col3] [char](200) NULL
)
CREATE NONCLUSTERED INDEX IX_Table1 ON Table1 (col1 ASC)
Run Code Online (Sandbox Code Playgroud)

里面有一些数据:

INSERT INTO Table1(col1) VALUES (1),(2),(3),
                               (-9223372036854775808),
                               (9223372036854775807),
                               (2147483647),(-2147483648)
Run Code Online (Sandbox Code Playgroud)

当我运行以下(废话)查询时:

SELECT a.col1, a.col2
  FROM Table1 a, Table1 b
  WHERE b.col1 > 2147483648
Run Code Online (Sandbox Code Playgroud)

我看到它将在索引查找和标量计算(来自常量)的结果中执行嵌套循环绘图。

请注意,文字大于 maxint。它确实有助于编写CAST(2147483648 as BIGINT). 知道为什么 MSSQL 将其推迟到执行计划中,并且有没有比使用强制转换更短的方法来避免它?它是否也会影响到准备好的语句(来自 jtds JDBC)的绑定参数?

标量计算并不总是完成(似乎是索引查找特定的)。有时查询分析器不会以图形方式显示它,而是col1 < scalar(expr1000)在谓词属性中显示它。

我已经在 Windows 7 上的 MS SSMS 2016 …

sql-server execution-plan cast sql-server-2014

8
推荐指数
1
解决办法
295
查看次数

执行计划显示缺少索引但查询速度很快

在查看实际执行计划时,即使查询不到 1 秒,它也会显示缺少索引。

SELECT
    Account.AccountID,
    Account.Name
FROM
    account      
    LEFT OUTER JOIN accountfeaturesetting afs 
ON afs.accountid = account.accountid   
and afs.featureid = 'Schedules'
 and  
afs.settingid = 'EditReasons'           
WHERE
    ISNULL(afs.Value, '0') = '0'  
    AND EXISTS 
(SELECT 1 FROM program WHERE program.AccountID = account.AccountID
 AND program.Active = 1 
AND (program.ScheduleEditReasonFlags <> 0 
OR program.ScheduleEditReasonFields <> 0))
    AND account.IsMaster = 0
    AND account.BeginDate IS NOT NULL
Run Code Online (Sandbox Code Playgroud)

执行计划显示:

CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[Account] ([IsMaster],[BeginDate])
INCLUDE ([AccountID],[Name])
Run Code Online (Sandbox Code Playgroud)

即使查询只需要 1 秒,我们是否需要创建索引?应该在什么基础上创建索引?

我将把这个查询作为日常工作来运行。

index sql-server execution-plan

8
推荐指数
1
解决办法
842
查看次数

为什么我的查询在环境 A 中运行得很快,而在环境 B 中却很慢?

我有一段 SQL 似乎在环境 A 中运行得非常快,但完全相同的查询在环境 B 中运行得非常慢!

环境应该是相同的,所以我应该做什么和/或我应该在哪里查看查询为什么不执行相同?

performance sql-server execution-plan query-performance

7
推荐指数
2
解决办法
9392
查看次数

如何让交叉应用在视图上逐行操作?

我们有一个针对单项查询优化的视图(200 毫秒无并行性):

select * 
    from OptimizedForSingleObjectIdView e2i
   where ObjectId = 3374700
Run Code Online (Sandbox Code Playgroud)

它也适用于一小组静态 ID(~5)。

select * 
    from OptimizedForSingleObjectIdView e2i
   where ObjectId in (3374700, 3374710, 3374720, 3374730, 3374740);
Run Code Online (Sandbox Code Playgroud)

但是,如果对象来自外部源,那么它会生成一个缓慢的计划。执行计划显示视图部分的执行分支忽略了 ObjectId 上的谓词,而在原始情况下,它使用它们来执行索引查找。

select v.*
  from 
     (
       select top 1 ObjectId from Objects
        where ObjectId % 10 = 0
        order by ObjectId
     ) o  
  join OptimizedForSingleObjectIdView v -- (also tried inner loop join)
    on v.ObjectId = o.ObjectId;
Run Code Online (Sandbox Code Playgroud)

我们不希望投资于“双重”优化非奇异情况的视图。相反,我们“寻求”的解决方案是对每个对象重复调用一次视图,而无需求助于 SP

大多数情况下,以下解决方案会逐行调用视图。但是这次不是,甚至不是只有 1 个对象:

select v.*
  from
     (
       select top 1 ObjectId 
         from Objects …
Run Code Online (Sandbox Code Playgroud)

sql-server execution-plan view cross-apply

7
推荐指数
1
解决办法
1021
查看次数

重新排列 OR 条件时,SQL Server 创建不同的计划

我正在审查一个性能不佳的查询,如下所示:

WHERE manymany.Active = -1
  AND manymany.Check1 = -1
  AND manymany.WebsiteID = @P1
  AND CURRENT_TIMESTAMP BETWEEN ISNULL(manymany.FromDate, '1950-01-01') AND ISNULL(manymany.UptoDate, '2050-01-01')
  AND main.Active = -1
  AND main.StatusID = 1
  AND CURRENT_TIMESTAMP BETWEEN main.FromDate AND ISNULL(main.UptoDate, '2050-01-01')
  AND (main.TextCol1 IS NOT NULL OR main.TextCol2 IS NOT NULL)
ORDER BY aux.SortCode
Run Code Online (Sandbox Code Playgroud)

我不小心在这个查询上使用了 SSMS 查询设计器,它重新编写了查询,如下所示:

WHERE manymany.Active = -1
  AND manymany.Check1 = -1
  AND manymany.WebsiteID = @P2
  AND CURRENT_TIMESTAMP BETWEEN ISNULL(manymany.FromDate, '1950-01-01') AND ISNULL(manymany.UptoDate, '2050-01-01')
  AND main.Active = -1
  AND main.StatusID = 1 …
Run Code Online (Sandbox Code Playgroud)

sql-server optimization execution-plan sql-server-2012

7
推荐指数
1
解决办法
171
查看次数