防止使用临时表进行全表扫描

时间:2016-06-20 15:44:39

标签: sql-server tsql

我试图在一个大表中查找所有相关记录并根据较小的记录集更新它们,但是一旦我这样做,所有性能都会从窗口中消失并开始执行全表扫描大规模的桌子。

下面是导入file3后表格的示例(还有VoidID列和FileName的索引)

该表显示ID#1与ID#2相关,反之亦然,ID#4和#5相同。 ID#3是一个无效的销售。

导入File3之后​​,我想查找同一文件中存在销售和无效的所有记录,但仅针对刚刚导入的文件。所以我使用临时表#Results,我只从File3插入ID,但是当我将该临时表添加到查询中时,它会对表进行全面扫描并永远运行:

DECLARE @Import Table(ID int PRIMARY KEY NOT NULL, TransType varchar(10), VoidID int, FileName varchar(25))
INSERT INTO @Import
VALUES(1,'Sale',2,'File1'),(2,'Void',1,'File1'),(3,'Sale',NULL,'File2'),(4,'Sale',5,'File3'),(5,'Void',4,'File3')
SELECT * FROM @Import

CREATE table #Results(ID integer PRIMARY KEY NOT NULL)
INSERT INTO #Results(ID)
SELECT ID FROM @Import WHERE FileName = 'File3'

select * from #Results

SELECT P1.ID
FROM @Import P1 INNER JOIN #Results R ON P1.ID = R.ID INNER JOIN @Import P2 ON P1.ID = P2.VoidID
WHERE P1.FileName = P2.FileName

DROP TABLE #Results

这样可行,但全表扫描现在仍然在运行(超过一小时),所以这是不可接受的。估计的执行计划显示没有丢失的索引。

如何改进此查询?

**编辑实际查询,密钥和索引**

UPDATE P1
SET Notes = 'Matching Sale, Void in same file.'
FROM 
PriceImport P1 INNER JOIN 
#ResultSet R ON P1.ID = R.ID INNER JOIN 
PriceImport P2 ON P1.ID = P2.VoidID
WHERE P1.FileName = P2.FileName 


ALTER TABLE [dbo].[PriceImport] ADD  CONSTRAINT [PK_PriceImportID] PRIMARY KEY NONCLUSTERED 
(
    [ID] ASC
)WITH (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 [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [idx_PriceImport_Transaction_Matching] ON [dbo].[PriceImport]
(
    [TransType] ASC,
    [VoidID] ASC
)
INCLUDE ([ID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

1 个答案:

答案 0 :(得分:0)

我不需要#temp
我得到了你想做的事,但这不应该是必要的 请在真实的桌子上试试这个

select p2.id, P1.ID
  from table p1 
  join table p2
    on P1.ID = P2.VoidID
   and p1.filename = 'File3'
   and p2.filename = 'File3'

如果这些列被编入索引,则应该禁止吸烟

如果他们总是成对,你可以做

and p2.id < P1.ID

这应该很容易

你有VoidID作为第二个 - 没有开玩笑你有索引扫描
要么使它成为第一个,要么为VoidID具有单独的索引 你没有文件名索引 - 不开玩笑你正在进行表扫描

请将查询计划发布到此

UPDATE P1
SET Notes = 'Matching Sale, Void in same file.'
FROM PriceImport P1 
JOIN #ResultSet R 
       ON P1.ID = R.ID 
JOIN PriceImport P2 
       ON P1.ID       = P2.VoidID
      AND P1.FileName = P2.FileName 
      AND isnull(Notes, "") <> 'Matching Sale, Void in same file.'

如果文件名是#ResultSet那么这应该更好

UPDATE P1
SET Notes = 'Matching Sale, Void in same file.'
FROM PriceImport P1 
JOIN #ResultSet R1 
       ON P1.ID = R1.ID 
JOIN PriceImport P2 
       ON P1.ID = P2.VoidID
      AND isNull(Notes, "") <> 'Matching Sale, Void in same file.'   -- locks are expensive
JOIN #ResultSet R2 
       ON P2.ID = R2.ID 

您是否考虑过在#ResultSet中加载所有#ResultSet?