Sql server QL可以考虑使用聚集索引比使用非聚集索引更便宜,然后查找簇索引中的每个匹配行的ActueID。这是因为相对于顺序I/O,聚集索引查找非常昂贵,因此任何需要查找超过百分之几的行的计划都可能比扫描更便宜。无论如何,如果这确实是您所看到的问题,那么在IX_STAT_Statistieken_1索引中添加actieGroep作为INCLUDE-d列应该可以解决这个问题。像这样:
Sql server QL可以考虑使用聚集索引比使用非聚集索引更便宜,然后查找簇索引中的每个匹配行的ActueID。这是因为相对于顺序I/O,聚集索引查找非常昂贵,因此任何需要查找超过百分之几的行的计划都可能比扫描更便宜。无论如何,如果这确实是您所看到的问题,那么在IX_STAT_Statistieken_1索引中添加actieGroep作为INCLUDE-d列应该可以解决这个问题。像这样:,sql-server,tsql,indexing,Sql Server,Tsql,Indexing,在[dbo].[STAT\u Statistieken]上创建非聚集索引[IX\u Statistieken\u 1] ( [外来]描述, [secondaryId]ASC, [actieGroep]ASC, [Dagnumer]描述, [aantal]ASC )在[PRIMARY]上包含(actieId) 计算列actieGroep的数据类型是一个字符串,但您正在将其与WHERE子句和CASE语句中的整数(例如(1,2,3))进行比较。如果SQL决定转换列而不是常量,则会影响查询性能,并可能导
在[dbo].[STAT\u Statistieken]上创建非聚集索引[IX\u Statistieken\u 1]
(
[外来]描述,
[secondaryId]ASC,
[actieGroep]ASC,
[Dagnumer]描述,
[aantal]ASC
)在[PRIMARY]上包含(actieId)
当actieId介于0和9之间时,则actieId
当actieId在10和99之间时,则actieId/10
当激活ID在100和999之间时,则激活ID/100
当激活ID介于1000和9999之间时,则激活ID/1000
当激活ID介于10000和99999之间时,则激活ID/10000
当激活ID介于100000和999999之间时,则激活ID/100000
当激活ID介于1000000和9999999之间时,则激活ID/1000000
其他活动ID/10000000结束
select AU.*
FROM SYS.Allocation_units AS AU
INNER JOIN SYS.Partitions AS P
ON AU.Container_id = P.Partition_id
WHERE Object_ID = object_id('STAT_Statistieken')
尝试此操作并检查非聚集索引是否比聚集索引具有更多的页面(这意味着读取聚集索引更便宜)首先,我应该说您创建的索引不是最优的,因为它们只能用于过滤
异化的
SQL Server
无法执行跳过扫描
,并且索引中有一个secondaryId
,未使用范围条件进行筛选
因此,您在foreigned、actieGroep、dagNummer
上的条件不会产生有限的范围,也不完全可销售。它只能对异化的进行过滤,不能对整个集合进行过滤
现在,转到您当前的索引
我刚刚创建了您的表,并使用以下脚本用随机数据填充它们:
DROP TABLE STAT_Statistieken
CREATE TABLE [dbo].[STAT_Statistieken](
[statistiekId] [bigint] IDENTITY(1,1) NOT NULL,
[foreignId] [bigint] NOT NULL,
[datum] [datetime] NOT NULL, --date
[websiteId] [int] NOT NULL,
[actieId] [int] NOT NULL, --actionId
[objectSoortId] [int] NOT NULL, --kindOfObjectId
[aantal] [bigint] NOT NULL, --count
[secondaryId] [int] NOT NULL DEFAULT ((0)),
[dagnummer] AS (datediff(day,CONVERT([datetime],'2009-01-01 00:00:00.000',(121)),[datum])) PERSISTED, --daynumber
[actieGroep] AS (substring(CONVERT([varchar](4),[actieId],0),(1),(1))) PERSISTED,
CONSTRAINT [STAT_Statistieken_PK] PRIMARY KEY CLUSTERED --actionGroup
(
[statistiekId] ASC
)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_STAT_Statistieken_1] ON [dbo].[STAT_Statistieken]
(
[foreignId] DESC,
[secondaryId] ASC,
[actieGroep] ASC,
[dagnummer] DESC,
[aantal] ASC --count
)WITH (PAD_INDEX = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_STAT_Statistieken_2] ON [dbo].[STAT_Statistieken]
(
[foreignId] DESC,
[secondaryId] ASC,
[actieId] ASC,
[dagnummer] DESC,
[aantal] ASC -- count
)WITH (PAD_INDEX = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]
;WITH nums AS
(
SELECT 1 AS num
UNION ALL
SELECT num + 1
FROM nums
)
INSERT
INTO STAT_Statistieken (
[foreignId], [datum], [websiteId], [actieId],
[objectSoortId], [aantal])
SELECT TOP 100000
500, GETDATE(), num, num, num, num % 5
FROM nums
UNION ALL
SELECT TOP 100000
num % 1000, GETDATE(), num, num, num, num % 5
FROM nums
OPTION (MAXRECURSION 0)
UPDATE STATISTICS STAT_Statistieken
,它使用索引查找
,这很可能意味着问题出在数据分布上
我建议您创建一个附加索引,删除secondaryID
,如下所示:
ALTER PROCEDURE MyProcedure (@fid BIGINT)
AS BEGIN
DECLARE @fid_sniff BIGINT
SET @fid_sniff=@fid
SELECT foreignId
FROM STAT_Statistieken
WHERE foreignId = @fid_sniff
END
CREATE NONCLUSTERED INDEX [IX_STAT_Statistieken_1] ON [dbo].[STAT_Statistieken]
(
[foreignId] DESC,
[dagnummer] DESC,
[actieId] ASC,
[aantal] ASC
) INCLUDE (datum) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_STAT_Statistieken_3] ON [dbo].[STAT_Statistieken]
(
[foreignId] DESC,
[actieGroep] ASC,
[dagnummer] DESC,
[aantal] ASC --count
)
CREATE NONCLUSTERED INDEX [IX_STAT_Statistieken_2] ON [dbo].[STAT_Statistieken]
(
[foreignId] DESC,
[secondaryId] ASC,
[actieId] ASC,
[dagnummer] DESC,
[aantal] ASC -- count
)
INCLUDE (actieGroep);
WITH (PAD_INDEX = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]
如果仍要使用当前索引,请运行以下命令:
DBCC SHOW_STATISTICS ('STAT_Statistieken', 'IX_STAT_Statistieken_1')
DBCC SHOW_STATISTICS ('STAT_Statistieken', 'IX_STAT_Statistieken_2')
每个命令将输出三个结果集
请您发布每个命令的结果集
1
和2
,以及结果集3
的三行,其值RANGE\u HI
就在上面,就在下面,等于873926
?我以前见过类似的行为,它实际上会接受索引提示,并用它做更糟的事情(带书签查找的未筛选索引扫描)
这四项中的一项应该有帮助:
1) 附加-T4102-T4118到SQL Server 2005启动参数(可能适用于SQL 2008)。注意:这会导致SQL 2005中对IN和NOT IN查询的SQL 2000错误处理
2) 使用FULLSCAN更新统计信息[dbo].[STAT\U Statistieken]
3) 选项(MAXDOP 1)——有时并行性会导致生成非常愚蠢的查询
4) 确保索引处于联机状态
还请注意,如果要在存储过程中创建的表上创建索引,则在编译存储过程查询时该索引不存在,因此不会使用该索引。由于您的表是在dbo中全局创建的,所以我假设这里不是这样
编辑:有时我希望有一个真正的forceplan,您可以直接输入计划并执行任何可能的计划:类似于DB的汇编语言。尝试创建如下索引:
ALTER PROCEDURE MyProcedure (@fid BIGINT)
AS BEGIN
DECLARE @fid_sniff BIGINT
SET @fid_sniff=@fid
SELECT foreignId
FROM STAT_Statistieken
WHERE foreignId = @fid_sniff
END
CREATE NONCLUSTERED INDEX [IX_STAT_Statistieken_1] ON [dbo].[STAT_Statistieken]
(
[foreignId] DESC,
[dagnummer] DESC,
[actieId] ASC,
[aantal] ASC
) INCLUDE (datum) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_STAT_Statistieken_3] ON [dbo].[STAT_Statistieken]
(
[foreignId] DESC,
[actieGroep] ASC,
[dagnummer] DESC,
[aantal] ASC --count
)
CREATE NONCLUSTERED INDEX [IX_STAT_Statistieken_2] ON [dbo].[STAT_Statistieken]
(
[foreignId] DESC,
[secondaryId] ASC,
[actieId] ASC,
[dagnummer] DESC,
[aantal] ASC -- count
)
INCLUDE (actieGroep);
WITH (PAD_INDEX = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]
然后重新创建您的过程是存储过程的重点,以确定是否存在从STAT_Statistieken到另一个表的链接,或者存在多少这样的链接?不,这只是问题的抽象版本。我只想使用索引对表进行选择。表中只包含一堆bigints@Jan:可能是一个没有实际意义的问题,但您是否更新了统计数据、整理了索引(最明显的是聚集索引)碎片?如果我用有限的信息模拟模式,我就不会遇到它期望的问题。关于查询缓存/查询计划命中/参数的问题
select AU.*
FROM SYS.Allocation_units AS AU
INNER JOIN SYS.Partitions AS P
ON AU.Container_id = P.Partition_id
WHERE Object_ID = object_id('STAT_Statistieken')
DROP TABLE STAT_Statistieken
CREATE TABLE [dbo].[STAT_Statistieken](
[statistiekId] [bigint] IDENTITY(1,1) NOT NULL,
[foreignId] [bigint] NOT NULL,
[datum] [datetime] NOT NULL, --date
[websiteId] [int] NOT NULL,
[actieId] [int] NOT NULL, --actionId
[objectSoortId] [int] NOT NULL, --kindOfObjectId
[aantal] [bigint] NOT NULL, --count
[secondaryId] [int] NOT NULL DEFAULT ((0)),
[dagnummer] AS (datediff(day,CONVERT([datetime],'2009-01-01 00:00:00.000',(121)),[datum])) PERSISTED, --daynumber
[actieGroep] AS (substring(CONVERT([varchar](4),[actieId],0),(1),(1))) PERSISTED,
CONSTRAINT [STAT_Statistieken_PK] PRIMARY KEY CLUSTERED --actionGroup
(
[statistiekId] ASC
)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_STAT_Statistieken_1] ON [dbo].[STAT_Statistieken]
(
[foreignId] DESC,
[secondaryId] ASC,
[actieGroep] ASC,
[dagnummer] DESC,
[aantal] ASC --count
)WITH (PAD_INDEX = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_STAT_Statistieken_2] ON [dbo].[STAT_Statistieken]
(
[foreignId] DESC,
[secondaryId] ASC,
[actieId] ASC,
[dagnummer] DESC,
[aantal] ASC -- count
)WITH (PAD_INDEX = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]
;WITH nums AS
(
SELECT 1 AS num
UNION ALL
SELECT num + 1
FROM nums
)
INSERT
INTO STAT_Statistieken (
[foreignId], [datum], [websiteId], [actieId],
[objectSoortId], [aantal])
SELECT TOP 100000
500, GETDATE(), num, num, num, num % 5
FROM nums
UNION ALL
SELECT TOP 100000
num % 1000, GETDATE(), num, num, num, num % 5
FROM nums
OPTION (MAXRECURSION 0)
UPDATE STATISTICS STAT_Statistieken
CREATE NONCLUSTERED INDEX [IX_STAT_Statistieken_3] ON [dbo].[STAT_Statistieken]
(
[foreignId] DESC,
[actieGroep] ASC,
[dagnummer] DESC,
[aantal] ASC --count
)
DBCC SHOW_STATISTICS ('STAT_Statistieken', 'IX_STAT_Statistieken_1')
DBCC SHOW_STATISTICS ('STAT_Statistieken', 'IX_STAT_Statistieken_2')
CREATE NONCLUSTERED INDEX [IX_STAT_Statistieken_2] ON [dbo].[STAT_Statistieken]
(
[foreignId] DESC,
[secondaryId] ASC,
[actieId] ASC,
[dagnummer] DESC,
[aantal] ASC -- count
)
INCLUDE (actieGroep);
WITH (PAD_INDEX = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]