我有以下查询:
USE [AxReports]
GO
DECLARE @paramCompany varchar(3)
SET @paramCompany = 'adf'
SELECT stl.MAINSALESID,
st.DATAAREAID,
Sum(sl.SALESQTY) as 'Quantity',
Sum(sl.SALESQTY * sl.SALESPRICE) as 'SalesValue'
INTO #openrel
FROM
DynamicsV5Realtime.dbo.SALESTABLE st
INNER JOIN
DynamicsV5Realtime.dbo.SALESLINE sl
ON
sl.SALESID = st.SALESID
and sl.DATAAREAID = st.DATAAREAID
INNER JOIN
DynamicsV5Realtime.dbo.INVENTTABLE it
ON
it.ITEMID = sl.ITEMID
and it.DATAAREAID = sl.DATAAREAID
INNER JOIN
DynamicsV5Realtime.dbo.SALESTABLELINKS stl
ON
stl.SUBSALESID = st.SALESID
and stl.DATAAREAID = st.DATAAREAID
WHERE
st.DATAAREAID = @paramCompany
and st.SALESTYPE = 3 -- Release Order
and st.SALESSTATUS = 1
and sl.SALESSTATUS <> 4
and it.ITEMGROUPID <> 'G0022A'
GROUP BY
stl.MAINSALESID,
st.DATAAREAID
我的执行计划建议索引为:
USE [DynamicsV5Realtime]
GO
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[INVENTTABLE] ([DATAAREAID],[ITEMGROUPID])
INCLUDE ([ITEMID])
GO
但是我已经在该表上有一个类似于该计划正在使用的索引,但是对它执行表扫描。目前的指数如下:
CREATE NONCLUSTERED INDEX [I_ITEMGROUPIDX] ON [dbo].[INVENTTABLE]
(
[ITEMID] ASC,
[DATAAREAID] ASC
)
INCLUDE ( [ITEMGROUPID])
GO
我有一个理解,你不应该把事情作为一个包含的列,当你不打扰他们在叶级别排序时(我认为这是正确的吗?)。
在这种情况下,WHERE子句具有it.ITEMGROUPID&lt;&gt; 'G0022A'所以把它作为一个关键专栏是有道理的,因为按顺序寻找那个专栏会更快,(我认为我说的是对的吗?)
然而,为什么连接,为什么建议将ITEMID列作为包括而不是DATAAREAID列?在这种情况下,ITEMID和DATAAREAID组成了PK,因此它不需要对两列进行排序,也许可以使用现有索引,但将ITEMGROUPID作为关键列,是添加新索引的更好解决方案吗? (这就是我可以测试的东西)
由于
答案 0 :(得分:3)
让我们先考虑相对隔离的这个表;那就是我们只关注那些直接提到的查询部分。
执行查询需要执行以下操作:
INVENTTABLE
列中等于'G0022A'的ITEMGROUPID
中的所有行。DATAAREAID
和ITEMID
列的值,以便在SALESLINE
中查找必要的行。执行第一部分的最佳索引是ITEMGROUPID
但没有其他列的密钥。这样的密钥(我们现在将忽略包含的列)将使表扫描能够找到相关的行和仅那些行。
如果没有这样的索引但是有一个索引的ITEMGROUPID
作为其列之一,那么该索引可以用于表扫描,但效果不是很好。
现在,当我们考虑第二部分时,我们实际关心的唯一值是DATAAREAID
和ITEMID
。
如果包含这些字段,则可以在索引扫描中使用它们。
如果它们实际上是密钥的一部分,或者其中一个是,而另一个是,则该索引也可用于此类索引扫描。
因此。在这一点上,只考虑我们在此时会考虑的那些方面并忽略其他考虑因素(索引大小,插入成本等),那么以下任何索引在这里都很有用: / p>
CREATE NONCLUSTERED INDEX [someIndexName]
ON [dbo].[INVENTTABLE] ([ITEMGROUPID],[DATAAREAID],[ITEMID])
CREATE NONCLUSTERED INDEX [someIndexName]
ON [dbo].[INVENTTABLE] ([ITEMGROUPID])
INCLUDE ([DATAAREAID],[ITEMID])
CREATE NONCLUSTERED INDEX [someIndexName]
ON [dbo].[INVENTTABLE] ([ITEMGROUPID])
INCLUDE ([ITEMID],[DATAAREAID])
CREATE NONCLUSTERED INDEX [someIndexName]
ON [dbo].[INVENTTABLE] ([DATAAREAID],[ITEMGROUPID])
INCLUDE ([ITEMID])
CREATE NONCLUSTERED INDEX [someIndexName]
ON [dbo].[INVENTTABLE] ([ITEMID],[ITEMGROUPID])
INCLUDE ([DATAAREAID])
CREATE NONCLUSTERED INDEX [someIndexName]
ON [dbo].[INVENTTABLE] ([ITEMGROUPID],[DATAAREAID])
INCLUDE ([ITEMID])
CREATE NONCLUSTERED INDEX [someIndexName]
ON [dbo].[INVENTTABLE] ([ITEMGROUPID],[ITEMID])
INCLUDE ([DATAAREAID])
这些索引中的每一个都包含ITEMGROUPID
作为密钥的全部或部分,ITEMID
和DATAAREAID
作为密钥的一部分或作为包含的列。
请注意,他们所拥有的索引与此相反;它具有理想情况下作为包含列的键的列,其他列作为键的一部分。它总比没有好,查询计划程序可以重新开始使用它,但它并不是我们想要的最理想的关键。
现在,让我们考虑整个查询。
SALESTABLE
列搜索DATAAREAID
。SALESLINE
已在其自己的DATAAREAID
列上加入该列。INVENTTABLE
依据自己的SALESLINE
列加入DATAAREAID
上的该列。由此我们可以推断,我们逻辑上只希望来自INVENTTABLE
的{{1}}列中包含值为@paramCompany
的记录。
计划者做了这个演绎。
因此,考虑到整个查询,我们可以将上面的两个操作更改为:
DATAAREAID
列中INVENTTABLE
列等于'G0022A'且ITEMGROUPID
等于DATAAREAID
的所有行。@paramCompany
(已在步骤1中获得)和DATAAREAID
列的值。因此理想的指数是:
ITEMID
OR
CREATE NONCLUSTERED INDEX [someName]
ON [dbo].[INVENTTABLE] ([ITEMGROUPID],[DATAAREAID])
INCLUDE ([ITEMID])
GO
(或者包含密钥中所有三个密钥的密钥,但如果您实际上不需要密钥,则还有其他原因没有大密钥。)
第二个确实是你的建议。
答案 1 :(得分:0)
对Google来说这应该很容易,但我想说基本上只有索引中的连接中使用的列并包含返回列,这样就不需要对实际表进行查找(包括在索引中)。 我会说建议可能或多或少可靠,可能是因为统计数据不好或其他什么,不要盲目依赖它们。此外,我认为当运算符为'&lt;&gt;'时,不能使用索引。