2017-04-05 44 views
2

我有一个查询需要优化,我不知道如何。这是SQL脚本:优化sql除查询

declare @tempTable table(color1 int, color2 int, color3 int, color4 int, newToken uniqueidentifier default newid(), ordinal int identifier(1,1)) 

insert into @tempTable 
select color1, color2, color3, color4 
from @colorCombination 
except 
select c1.color as color1, c2.color as color2, c3.color as color3, c4.color as color4 
from products p 
inner join attributes c1 on c1.pId = p. Id and c1.type = 'primary' 
inner join attributes c2 on c2.pId = p. Id and c2.type = 'secondary' 
inner join attributes c3 on c3.pId = p. Id and c3.type = 'other1' 
inner join attributes c4 on c4.pId = p. Id and c4.type = 'other2' 
where p.category = 'furniture' 

没有除,无论select语句运行非常快,但与不同的,花了将近15分钟

@colorCombination拥有近24000行

的productattributes返回11000行

我使用除了因为需要找到那些尚未在数据库中的13,000然后插入它。

这是SQL Server上运行的2008

有没有更好的方式来获得缺失的记录,而不是使用除了

回答

2

这么少的行的糟糕表现是由表变量以及它们如何影响执行计划造成的。

此答案在(color1, color2, color3, color4)上使用非聚集索引的临时表。您的原始表格变量没有为任何颜色指定not null,所以我将假定某些null值是可以接受的。如果不是,您可以删除代理Id并在四个颜色列上使用聚簇索引。为了允许空值,这也切换回except而不是not exists()。如果null不是一个因素,那么not exists()应该快一点。


/* step 1: existing colors in a temp table with an index */ 

create table #productColors (
    id int not null identity (1,1) primary key clustered 
    , color1 int , color2 int , color3 int , color4 int 
); 

insert into #productColors (color1, color2, color3, color4) 
select distinct 
    color1 = case when c.[type] = 'primary' then c.color end 
    , color2 = case when c.[type] = 'secondary' then c.color end 
    , color3 = case when c.[type] = 'other1' then c.color end 
    , color4 = case when c.[type] = 'other2' then c.color end 
from from products p 
    inner join attributes c 
    on p.Id = c.Id 
group by p.id; 

create nonclustered index ix_productColors 
    on #productColors (color1, color2, color3, color4); 

/* step 2: color combinations in a temp table with an index */ 

create table #colorCombinations (
    id int not null identity (1,1) primary key clustered 
    , color1 int , color2 int , color3 int , color4 int 
); 

insert into #colorCombinations (color1, color2, color3, color4) 
select distinct color1 , color2 , color3 , color4 
from @colorCombinations; 

create nonclustered index ix_colorCombinations 
    on #colorCombinations (color1, color2, color3, color4); 

/* step 3: insert new color combinations into #tempTable */ 

create table #tempTable (color1 int 
    , color2 int 
    , color3 int 
    , color4 int 
    , newToken uniqueidentifier default newid() 
    , ordinal int identifier(1,1) 
); 

insert into #tempTable(color1, color2, color3, color4) 
    select color1, color2, color3, color4 
    from #colorCombination 
    except 
    select color1, color2, color3, color4 
    from #productColors 
:关于表变量和临时表

参考


老答案:

使用except也去复制的行你@tempTable(这可能是最好的,而不是#temptable@TableVariable这取决于你如何使用它)。

如果你不需要从@tempTable删除重复的行,那么你可以使用not exists()(或添加distinctselect,但它会采取的性能损失):

insert into @tempTable 
select color1, color2, color3, color4 
from @colorCombination cc 
where not exists (
    select 1 
    from products p 
    inner join attributes c1 on c1.pId = p. Id and c1.type = 'primary' 
    inner join attributes c2 on c2.pId = p. Id and c2.type = 'secondary' 
    inner join attributes c3 on c3.pId = p. Id and c3.type = 'other1' 
    inner join attributes c4 on c4.pId = p. Id and c4.type = 'other2' 
    where p.category = 'furniture' 
    and c1.color = cc.color1 
    and c2.color = cc.color2 
    and c3.color = cc.color3 
    and c4.color = cc.color4 
) 
+0

我还喜欢询问为什么使用临时表/表变量?除非查询结果需要多次使用,否则我会消除该部分并直接使用查询......但这取决于更宏观的目的。 –

+0

感谢您的快速响应!我稍后再尝试,并让你知道。非常感谢。我编辑了脚本,它具有临时表的列。在插入后,我需要批量插入缺失的行在3个表 –

+0

我试过不存在..可悲的是现在需要16分钟的时间 –