这是主键中指定的排序顺序的衍生问题,但排序是在 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) 我有两个存储过程。这个速度非常快(约 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
考虑以下查询:
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
我有两个相当简单的查询。第一个查询
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
我有一个长时间运行的查询(有 1 亿行的事实表加入了一些小的暗表然后分组),它溢出到 tempdb,即使(经过一些调整)CE 非常接近实际的行数,请参阅计划:
寻找解释,我注意到以下内存授予信息:
环境:SQL Server 2012 SP1 Enterprise,服务器 RAM 256 GB,SQL Server 最大内存 200 GB,缓冲池大小 42 GB,工作区最大大小 156 GB(GrantedMemory = 156 * 25% ~= 38 GB)
Paste The Plan 上的匿名查询计划
强制哈希匹配聚合(而不是排序 + 流聚合)时,查询始终快 3 - 4 倍。不幸的是,实际查询来自 Cognos,我们无法更改它。
散列聚合计划中没有散列溢出。查询优化器不会选择散列匹配聚合,因为如果我查看散列与流聚合的运算符成本,散列组的 CPU 成本比进行流聚合高 2 - 3 倍。
在流和哈希聚合中,估计的输出行与输入(约 1 亿行)完全相同。
查询使用单个 NC 列存储索引,并且列统计信息都定期更新。
当我查看一些查询的实际执行计划时,我注意到 WHERE 子句中使用的文字常量显示为计算标量和常量 scan的嵌套链。
为了重现这一点,我使用下表
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 …
在查看实际执行计划时,即使查询不到 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 秒,我们是否需要创建索引?应该在什么基础上创建索引?
我将把这个查询作为日常工作来运行。
我有一段 SQL 似乎在环境 A 中运行得非常快,但完全相同的查询在环境 B 中运行得非常慢!
环境应该是相同的,所以我应该做什么和/或我应该在哪里查看查询为什么不执行相同?
我们有一个针对单项查询优化的视图(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) 我正在审查一个性能不佳的查询,如下所示:
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) execution-plan ×10
sql-server ×9
performance ×3
index ×2
sorting ×2
cast ×1
cross-apply ×1
optimization ×1
parameter ×1
postgresql ×1
tempdb ×1
view ×1