标签: execution-plan

如何衡量或查找创建查询计划的成本?

我有一个典型的例子,参数嗅探导致一个“坏”的执行计划进入计划缓存,导致我的存储过程的后续执行非常缓慢。我可以用局部变量OPTIMIZE FOR ... UNKNOWN、 和来“解决”这个问题OPTION(RECOMPILE)。但是,我也可以深入查询并尝试优化它。

我正在尝试确定我是否应该:鉴于解决问题的时间有限,我想知道这样做的成本。在我看来,如果我坚持使用OPTION(RECOMPILE),净效果是每次运行查询时都会重新创建查询计划。所以,我想我需要知道:

如何找出创建查询计划的成本是多少?

为了回答我自己的问题,我在谷歌上搜索过(例如使用这个查询),并且我已经浏览了dm_exec_query_statsDMV列的文档 。我还检查了 SSMS 中的“实际查询计划”的输出窗口以找到此信息。最后,我搜索了 DBA.SE。这些都没有得到答案。

谁能告诉我?是否可以找到或测量创建计划所需的时间?

sql-server execution-plan

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

索引不与 = ANY() 一起使用,但与 IN 一起使用

t有两个索引:

create table t (a int, b int);
create type int_pair as (a int, b int);
create index t_row_idx on t (((a,b)::int_pair));
create index t_a_b_idx on t (a,b);

insert into t (a,b)
select i, i
from generate_series(1, 100000) g(i)
;
Run Code Online (Sandbox Code Playgroud)

ANY运算符不使用索引:

explain analyze
select *
from t
where (a,b) = any(array[(1,1),(1,2)])
;
                                            QUERY PLAN                                             
---------------------------------------------------------------------------------------------------
 Seq Scan on t  (cost=0.00..1693.00 rows=1000 width=8) (actual time=0.042..126.789 rows=1 loops=1)
   Filter: (ROW(a, b) = ANY (ARRAY[ROW(1, 1), ROW(1, 2)]))
   Rows Removed …
Run Code Online (Sandbox Code Playgroud)

postgresql index optimization execution-plan postgresql-9.4

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

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

我正在运行一个查询,该查询给出有关内存的警告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
查看次数

CROSS APPLY 产生外连接

为了回答分区上不同的 SQL 计数, Erik Darling 发布了此代码以解决以下问题COUNT(DISTINCT) OVER ()

SELECT      *
FROM        #MyTable AS mt
CROSS APPLY (   SELECT COUNT(DISTINCT mt2.Col_B) AS dc
                FROM   #MyTable AS mt2
                WHERE  mt2.Col_A = mt.Col_A
                -- GROUP BY mt2.Col_A 
            ) AS ca;
Run Code Online (Sandbox Code Playgroud)

查询使用CROSS APPLY(not OUTER APPLY) 那么为什么在执行计划中有连接而不是连接?

在此处输入图片说明

另外,为什么取消注释 group by 子句会导致内部联接?

在此处输入图片说明

我不认为数据很重要,而是从 kevinwhat 在另一个问题上提供的数据中复制:

create table #MyTable (
Col_A varchar(5),
Col_B int
)

insert into #MyTable values ('A',1)
insert into #MyTable values ('A',1)
insert into …
Run Code Online (Sandbox Code Playgroud)

sql-server execution-plan cross-apply

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

SQL Server 2016 Bad Query Plan 每周锁定一次数据库

每周一次,在过去 5 周内,大约在一天中的同一时间(清晨,可能基于人们开始使用它时的用户活动),SQL Server 2016(AWS RDS,镜像)开始超时很多查询。

所有表上的 UPDATE STATISTICS 总是立即修复它。

在第一次之后,我让它每晚(而不是每周)更新所有表上的所有统计信息,但它仍然发生了,(更新统计信息运行后大约 8 小时,但不是每天运行)。

这最后一次,我启用了查询存储,看看我是否能找到它是哪个特定的查询/查询计划。我想我可以将其缩小为一个:

错误的查询计划

找到该查询后,我添加了一个推荐索引,该索引在这个不常用的查询中缺失(但它确实触及了很多常用表)。

错误的查询计划正在执行索引扫描(在只有 10k 行的表上)。其他以毫秒为单位返回的查询计划,虽然用于执行相同的扫描。最新的查询计划,在创建新索引后只查找。但即使没有该索引,99% 的情况下,它也会在几毫秒内返回,但是,每周需要超过 40 秒。

这是从 2012 年迁移到 SQL Server 2016 后开始发生的。

DBCC CHECKDB 没有返回错误。

  1. 新索引是否会解决问题,使其不再选择糟糕的计划?
  2. 我应该“强制”现在运行良好的计划吗?
  3. 我如何确保这不会发生在另一个查询/计划中?
  4. 这是更大问题的征兆吗?

我刚刚添加的索引:

CREATE NONCLUSTERED INDEX idx_AppointmetnAttendee_AttendeeType
ON [dbo].[AppointmentAttendee] ([UserID],[AttendeeType])

CREATE NONCLUSTERED INDEX [idx_appointment_start] ON [dbo].[Appointment]
(
    [ProjectID] ASC,
    [Start] ASC
)
INCLUDE (   [ID],
    [AllDay],
    [End],
    [Location],
    [Notes],
    [Title],
    [CreatedByID]) WITH (PAD_INDEX = OFF, …
Run Code Online (Sandbox Code Playgroud)

sql-server statistics execution-plan sql-server-2016 query-store

17
推荐指数
1
解决办法
8672
查看次数

强制索引假脱机

我知道出于性能原因应该避免它,但我试图展示一个条件,它显示为演示如何确保它不会出现。

但是,我最终得到了缺少索引警告,但优化器选择不创建临时索引。

我正在使用的查询是

SELECT 
    z.a
FROM dbo.t5 AS z WITH(INDEX(0))
WHERE 
    EXISTS 
    (
        SELECT y.a 
        FROM dbo.t4 AS y
        WHERE y.a = z.a
    )
OPTION (MAXDOP 1);
Run Code Online (Sandbox Code Playgroud)

表模式是:

CREATE TABLE dbo.t4
(
    a   integer NULL,
    b   varchar(1000) NULL,
    p   varchar(100) NULL
);

CREATE TABLE dbo.t5
(
    a   integer NULL,
    b   varchar(1000) NULL
);

CREATE UNIQUE CLUSTERED INDEX c1 
ON dbo.t5 (a);
Run Code Online (Sandbox Code Playgroud)

两个表都有 10,000 行,您可以使用以下方法进行模拟:

UPDATE STATISTICS dbo.t4 
WITH 
    ROWCOUNT = 10000, 
    PAGECOUNT = 1000;

UPDATE STATISTICS dbo.t5 
WITH 
    ROWCOUNT = …
Run Code Online (Sandbox Code Playgroud)

t-sql execution-plan sql-server-2012 index-spool

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

如何使用执行计划优化 T-SQL 查询

我有一个 SQL 查询,我花了两天时间尝试使用试错法和执行计划进行优化,但无济于事。请原谅我这样做,但我会在这里发布整个执行计划。我已经努力使查询和执行计划中的表名和列名通用,既为了简洁又为了保护我公司的 IP。可以使用SQL Sentry Plan Explorer打开执行计划。

我已经完成了大量的 T-SQL,但是使用执行计划来优化我的查询对我来说是一个新领域,我真的试图了解如何去做。所以,如果有人能帮我解决这个问题并解释如何破译这个执行计划以在查询中找到优化它的方法,我将永远感激不尽。我还有更多的查询需要优化——我只需要一个跳板来帮助我完成第一个查询。

这是查询:

DECLARE @Param0 DATETIME     = '2013-07-29';
DECLARE @Param1 INT          = CONVERT(INT, CONVERT(VARCHAR, @Param0, 112))
DECLARE @Param2 VARCHAR(50)  = 'ABC';
DECLARE @Param3 VARCHAR(100) = 'DEF';
DECLARE @Param4 VARCHAR(50)  = 'XYZ';
DECLARE @Param5 VARCHAR(100) = NULL;
DECLARE @Param6 VARCHAR(50)  = 'Text3';

SET NOCOUNT ON

DECLARE @MyTableVar TABLE
(
    B_Var1_PK int,
    Job_Var1 varchar(512),
    Job_Var2 varchar(50)
)

INSERT INTO @MyTableVar (B_Var1_PK, Job_Var1, Job_Var2) 
SELECT B_Var1_PK, Job_Var1, Job_Var2 FROM [fn_GetJobs] (@Param1, @Param2, @Param3, @Param4, …
Run Code Online (Sandbox Code Playgroud)

sql-server-2008 sql-server optimization t-sql execution-plan

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

使用 SqlCommand.Prepare() 的意义和好处是什么?

我遇到了开发人员代码,其中 SqlCommand.Prepare() (参见 MSDN)方法在执行 SQL 查询之前被广泛使用。我想知道这样做有什么好处?

样本:

command.Prepare();
command.ExecuteNonQuery();
//...
command.Parameters[0].Value = 20;
command.ExecuteNonQuery();
Run Code Online (Sandbox Code Playgroud)

我玩了一点并进行了追踪。调用Prepare()方法后执行Command,使Sql Server执行如下语句:

declare @p1 int
set @p1=1
exec sp_prepexec @p1 output,N'@id int,@desc text',N'INSERT INTO dbo.testtable (id) VALUES (@id)',@id=20'
select @p1
Run Code Online (Sandbox Code Playgroud)

之后,当 Parameter 获取它的值并被SqlCommand.ExecuteNonQuery()调用时,将在 Sql-Server 上执行以下操作:

exec sp_execute 1,@id=20
Run Code Online (Sandbox Code Playgroud)

对我来说,这看起来就像语句在Prepare()执行时被编译。我想知道这样做有什么好处?这是否意味着它被放入计划缓存中,并且可以在使用所需参数值执行最终查询后立即重新使用?

我发现(并在另一个问题中记录了它)使用 SqlParameters 执行的 SqlCommands 总是包含在sp_executesql过程调用中。这使得 Sql Server 能够独立于参数值存储和重用计划。

关于这一点,我想知道该prepare()方法是无用的还是过时的,或者我在这里遗漏了什么?

sql-server execution-plan sql-server-2008-r2 prepared-statement plan-cache

16
推荐指数
2
解决办法
5350
查看次数

对可读次要的强制计划

如果在可用性组中的主节点上强制执行计划,它是否应用于在辅助节点上运行的查询?

我正在寻找涵盖计划强制两种可能性的答案:

我已阅读以下内容,这些内容表明 QS 强制计划不会结转,但在文档中找不到任何权威信息,或任何有关计划指南的信息。

强制的决定性证据是辅助节点的执行计划中存在Use PlanPlanGuideNamePlanGuideDB属性。

sql-server execution-plan availability-groups query-store plan-guides

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