1

我正在尝试在 SQL Server 中编写查询,但它正在对具有大约 3000 万行 (TGS_INFO) 的表进行表扫描,因此查询运行非常缓慢。

实际查询更复杂,但我已将其简化为仍然存在相同问题的更简单版本。

SELECT DISTINCT UNIT_ITEMS.DBKEY,
    UNIT_ITEMS.ID,
    UNIT_ITEMS.LOCATION1,
    UNIT_ITEMS.LOCATION2
FROM UNIT_ITEMS
INNER JOIN TGS.dbo.TGS_INFO
ON UNIT_ITEMS.UNIT_ID = TGS_INFO.UNIT_ID AND
    UNIT_ITEMS.ITEM_ID = TGS_INFO.ITEM_ID AND
    UNIT_ITEMS.LOCATION1 = TGS_INFO.LOCATION1 AND
    UNIT_ITEMS.LOCATION2 = TGS_INFO.LOCATION2

这是执行计划。

StmtText
  |--Sort(DISTINCT ORDER BY:([DbName].[dbo].[UNIT_ITEMS].[DBKEY] ASC, [DbName].[dbo].[UNIT_ITEMS].[ITEM_ID] ASC, [DbName].[dbo].[UNIT_ITEMS].[LOCATION1] ASC, [DbName].[dbo].[UNIT_ITEMS].[LOCATION2] ASC))
       |--Hash Match(Inner Join, HASH:([DbName].[dbo].[UNIT_ITEMS].[UNIT_ID], [DbName].[dbo].[UNIT_ITEMS].[ITEM_ID], [DbName].[dbo].[UNIT_ITEMS].[LOCATION1], [DbName].[dbo].[UNIT_ITEMS].[LOCATION2])=([Expr1008], [Expr1009], [Expr1010], [Expr1011]), RESIDUAL:([DbName].[dbo].[UNIT_ITEMS].[UNIT_ID]=[Expr1008] AND [DbName].[dbo].[UNIT_ITEMS].[ITEM_ID]=[Expr1009] AND [DbName].[dbo].[UNIT_ITEMS].[LOCATION1]=[Expr1010] AND [DbName].[dbo].[UNIT_ITEMS].[LOCATION2]=[Expr1011]))
            |--Table Scan(OBJECT:([DbName].[dbo].[UNIT_ITEMS]))
            |--Compute Scalar(DEFINE:([Expr1008]=CONVERT_IMPLICIT(int,[TGS].[dbo].[TGS_INFO].[UNIT_ID],0), [Expr1009]=CONVERT_IMPLICIT(nvarchar(50),[TGS].[dbo].[TGS_INFO].[ITEM_ID],0), [Expr1010]=CONVERT_IMPLICIT(nvarchar(50),[TGS].[dbo].[TGS_INFO].[LOCATION1],0), [Expr1011]=CONVERT_IMPLICIT(int,[TGS].[dbo].[TGS_INFO].[LOCATION2],0)))
                 |--Table Scan(OBJECT:([TGS].[dbo].[TGS_INFO]))

TGS_INFO 和 UNIT_ITEMS 在 UNIT_ID 和 ITEM_ID 上都有非聚集索引。如前所述,TGS_INFO 有大约 3000 万行,但它们均匀分布在大约一千个不同的 UNIT_ID 周围。UNIT_ITEMS 始终只包含一个 UNIT_ID。

以下是索引:

CREATE NONCLUSTERED INDEX [IX_UNIT_ID_ITEM_ID] ON [dbo].[TGS_INFO] 
(
    [UNIT_ID] ASC,
    [ITEM_ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IX_UNIT_ID_ITEM_ID] ON [dbo].[UNIT_ITEMS] 
(
    [UNIT_ID] ASC,
    [ITEM_ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

正如我在评论中提到的,所有列都是 TGS_INFO 中的 VARCHAR(50)。UNIT_ITEMS 中的所有列都是整数。

作为记录,我没有设计 TGS_INFO 的模式。

4

2 回答 2

3

如果您没有在索引中包含LOCATION1LOCATION2,则无法仅从索引中满足连接。将这些列添加到两个表的索引中。

您可能还必须包括查询中引用的所有其他列。

于 2013-01-14T19:29:22.210 回答
0

我注意到执行计划显示以下内容:

|--Compute Scalar(DEFINE:([Expr1008]=CONVERT_IMPLICIT(int,[TGS].[dbo].[TGS_INFO].[UNIT_ID],0), [Expr1009]=CONVERT_IMPLICIT(nvarchar(50),[TGS].[dbo].[TGS_INFO].[ITEM_ID],0), [Expr1010]=CONVERT_IMPLICIT(nvarchar(50),[TGS].[dbo].[TGS_INFO].[LOCATION1],0), [Expr1011]=CONVERT_IMPLICIT(int,[TGS].[dbo].[TGS_INFO].[LOCATION2],0)))

我想不出查询引擎对这些列进行隐式数据类型转换的充分理由,除非两个表之间的数据类型与您用于连接的列不匹配。

您也可以尝试移至UNIT_ITEMS.LOCATION1 = TGS_INFO.LOCATION1 AND UNIT_ITEMS.LOCATION2 = TGS_INFO.LOCATION2WHERE子句,因为它们没有被索引覆盖。查询引擎通常足够聪明,可以解决这个问题,但这是值得尝试的。

于 2013-01-14T20:03:00.857 回答