我正在修复 SQL Server 中多语句存储过程的性能问题。我想知道我应该花时间在哪一部分上。
我从如何阅读查询成本中了解到,它总是一个百分比吗?即使当 SSMS 被告知包括实际执行计划时,“查询成本(相对于批次)”数字仍然基于成本估算,这可能与实际情况相差甚远
我从测量查询性能:“执行计划查询成本”与“所用时间”中了解到,我可以用SET STATISTICS TIME语句包围存储过程的调用,然后我将在Messages窗格中获得如下列表:
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 1 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
[etc]
SQL Server Execution Times:
CPU time = 187 ms, elapsed time = 206 ms.
Run Code Online (Sandbox Code Playgroud)
每个语句都有一个输出消息。
我可以“轻松”(虽然不方便)将时间统计输出与 Execution plan 窗格中的逐个语句执行计划相关联,方法是对它们进行计数:第四条SQL Server Execution Times消息输出对应Query …
performance sql-server ssms execution-plan query-performance
据我了解,SQL Server(或任何其他 RDBMS,实际上)中的查询优化器不知道数据库下存储的性能,并且会做出决策,好像所有存储的成本都相同。这是准确的,还是有一些考虑到存储性能的知识?
在一个完全人为设计的示例中,假设我的表行以瞬时访问时间存储在 SAN 中的 SSD 驱动器上,其中我的索引存储在极度过载的 SAS 驱动器上,从而导致磁盘饱和和恒定的磁盘队列。当 RDBMS 生成执行计划时,它是否比索引操作更倾向于表扫描(或者可能是瘦索引和关联的表查找,而不是覆盖索引,因为它在 SAS 磁盘上的 IO 较少)?
我怀疑答案是可靠的“优化器不可能聪明甚至意识到磁盘性能”,但我只是想看看是否有人确切知道。我正在使用 SQL Server,但我对任何数据库系统都感兴趣。
我有一张表,其中包含家庭的详细信息,而另一个表则包含与这些家庭相关的所有人员的详细信息。对于家庭表,我使用其中的两列定义了一个主键 - [tempId,n]。对于 person 表,我有一个使用其 3 列定义的主键[tempId,n,sporder]
使用主键上的聚集索引所指示的排序,我为每个家庭[HHID]和每个人的[PERID]记录生成了一个唯一 ID (下面的代码片段用于生成 PERID]:
ALTER TABLE dbo.persons
ADD PERID INT IDENTITY
CONSTRAINT [UQ dbo.persons HHID] UNIQUE;
Run Code Online (Sandbox Code Playgroud)
现在,我的下一步是将每个人与相应的家庭相关联,即;将 a 映射[PERID]到 a [HHID]。两个表之间的人行横道基于两列[tempId,n]。为此,我有以下内部连接语句。
UPDATE t1
SET t1.HHID = t2.HHID
FROM dbo.persons AS t1
INNER JOIN dbo.households AS t2
ON t1.tempId = t2.tempId AND t1.n = t2.n;
Run Code Online (Sandbox Code Playgroud)
我总共有1928783个户籍记录和5239842个人记录。执行时间目前非常高。
现在,我的问题:
我已将SQL Server 2008 为整个脚本生成的执行计划上传到 SQLPerformance.com
基于这些问题和给出的答案:
SQL 2008 Server - 性能损失可能与非常大的表有关
包含历史数据的大表分配了过多的 SQL Server 2008 Std。内存 - 其他数据库的性能损失
我在数据库 SupervisionP 中有一个表,定义如下:
CREATE TABLE [dbo].[PenData](
[IDUkazatel] [smallint] NOT NULL,
[Cas] [datetime2](0) NOT NULL,
[Hodnota] [real] NULL,
[HodnotaMax] [real] NULL,
[HodnotaMin] [real] NULL,
CONSTRAINT [PK_Data] PRIMARY KEY CLUSTERED
(
[IDUkazatel] ASC,
[Cas] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[PenData] WITH NOCHECK ADD CONSTRAINT [FK_Data_Ukazatel] FOREIGN KEY([IDUkazatel])
REFERENCES [dbo].[Ukazatel] ([IDUkazatel]) …Run Code Online (Sandbox Code Playgroud) performance sql-server-2008 sql-server execution-plan query-performance
我有两个存储过程。这个速度非常快(约 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
我正在尝试SQLite3使用json_extract表达式在(3.18) 中创建索引。我的目标是执行只需要索引才能产生结果的查询。这样做的原因是这json_extract是一项昂贵的操作,在对较大的数据集和/或值进行操作时会影响性能。我得出结论,我需要一个覆盖索引来满足我的需求。
第 1 步 - 使用正常的表结构测试理论
CREATE TABLE Player (
Id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
FirstName TEXT NOT NULL,
MiddleName TEXT,
LastName TEXT NOT NULL
);
CREATE INDEX Player_FirstName ON Player (
FirstName ASC,
LastName ASC
);
EXPLAIN QUERY PLAN SELECT
FirstName, LastName
FROM
Player
WHERE
LENGTH(LastName) > 10
ORDER BY
FirstName
LIMIT
10
OFFSET
0
Run Code Online (Sandbox Code Playgroud)
产量
SCAN TABLE Player USING COVERING INDEX Player_FirstName
Run Code Online (Sandbox Code Playgroud)
这正是我所期望的。Player_FirstName由于该ORDER BY子句,查询计划器认为索引是合适的,并且由于该WHERE …
存储过程查询有时会在其中一个表上的统计信息更新后得到一个糟糕的计划,但之后可以立即重新编译为好的计划。相同的编译参数。
问题似乎来自在 SP 中创建然后加入的一个小临时表。错误的计划在临时表上有一个警告,即连接列没有统计信息。是什么赋予了?
SQL Server 2016 SP1 CU4,具有 2014 兼容级别
糟糕的计划:
好计划:
USE AppDB
GO
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
GO
CREATE PROCEDURE [MySchema].[MySP]
@MyId VARCHAR(50),
@Months INT
AS
BEGIN
SET NOCOUNT ON
SELECT *
INTO #MyTemp
FROM AppDB.MySchema.View_Feeder vf WITH (NOLOCK)
WHERE vf.MyId = @MyId AND vf.Status IS NOT NULL
SELECT wd.Col1
, vp.Col2
, vp.Col3
FROM AppDB.MySchema.View_VP vp WITH (FORCESEEK)
INNER JOIN #MyTemp wd ON wd.Col1 = vp.Col1
WHERE vp.Col3 > DATEADD(MONTH, @Months * -1, …Run Code Online (Sandbox Code Playgroud) sql-server optimization statistics execution-plan temporary-tables
由于特定查询使用了错误的执行计划,我遇到了 100% CPU 峰值的大问题。我现在花了几个星期自己解决。
我的示例数据库包含 3 个简化表。
CREATE TABLE [model].[DataLogger](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[ProjectID] [bigint] NULL,
CONSTRAINT [PK_DataLogger] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
CREATE TABLE [model].[Inverter](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[SerialNumber] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_Inverter] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY],
CONSTRAINT [UK_Inverter] UNIQUE NONCLUSTERED
(
[DataLoggerID] ASC,
[SerialNumber] ASC
)WITH …Run Code Online (Sandbox Code Playgroud) performance execution-plan sql-server-2016 query-performance
我读到只有Trivial Plans 可以是 Simple Parameterized,并且并非所有查询(即使计划是 Trivial )都可以是 Simple Parameterized。
那么为什么这个计划同时显示了全面优化和简单参数化?
sql-server execution-plan trivial-plan simple-parameterization
execution-plan ×10
sql-server ×7
performance ×4
optimization ×3
ssms ×2
index ×1
join ×1
parameter ×1
sqlite ×1
statistics ×1
storage ×1
trivial-plan ×1