查询性能调优
Performance tuning of query
我有一个需要很长时间才能完成的查询 运行。可能是因为我在连接条件中使用了太多isnulls
。如何通过删除 isnull
?
来优化它
有没有不更新 table 的替代方法?查询如下:
select pos.C_id
,pos.s_id
,pos.A_id
,pos.Ad_id
,pos.Pr_id
,pos.prog_id
,pos.port_id
,pos.o_type
,pos.o_id
,pos.s_id
,pos.c_id
,pos.s_type_id
,pos.s_type
,pos.e_date
,pos.mv
,0 is_pub
, 1 is_adj
,pos.is_unsup
,getdate() date
,getdate() timestamp
from #temp pos
left join acc c with(nolock) ON pos._id = c.c_id
AND pos.account_id = c.account_id
AND isnull(pos.Pr_id,0) = isnull(c.pr_id,0)
AND isnull(pos.prog_id,0) = isnull(c.prog_id,0)
AND isnull(pos.port_id,0) = isnull(c.port_id,0)
and isnull(pos.style_type_id,0)=isnull(c.s_type_id,0)
AND pos.s_id = c._id
AND pos.c_id = c.c_id
AND pos.s_type = c.s_type
AND pos.is_unsup = c.is_uns
AND pos.is_pub = 1
where c.a_id is null
尝试使用
AND (pos.Pr_id = c.pr_id OR (pos.Pr_id IS NULL AND c.pr_id IS NULL))
而不是
AND ISNULL(pos.Pr_id,0) = ISNULL(c.pr_id,0)
IS NULL 比 ISNULL 更有效
您确实需要在临时 table #temp
上设置聚簇索引,如果不存在 sql-server 将为连接提供默认的 hash-based 索引,并且它对于大型 tables 来说性能不佳。
如果您在 #temp
table 中拥有的所有 id 列中的任何一个是唯一键,您确实需要在其上创建聚集索引:
CREATE CLUSTERED INDEX cx_temp ON #temp (YourIDColumn);
如果您在 #temp
中没有键列,请按以下方式为其添加身份主键:
1) 如果您使用 SELECT INTO
方法创建 #temp
,更改
select *
into #temp
from YourQuery
在
select IDENTITY (int, 1,1) ThisIsTheKey, *
into #temp
from YourQuery
-- and then add the index
CREATE CLUSTERED INDEX cx_temp ON #temp (ThisIsTheKey);
1) 如果您使用 CREATE TABLE
+ INSERT INTO
方法,只需像这样添加列:
CREATE TABLE #TEMP (
ThisIsTheKey INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
..
..
-- ALL YOUR OTHER COLUMNS
..
..
)
不要依赖覆盖非聚集索引,因为优化器可能不会使用它们,因为您选择的列太多。
首先测试聚簇索引,如果需要进一步优化可以尝试添加一些特定的非聚簇索引。
下面的查询呢
select pos.C_id
,pos.s_id
,pos.A_id
,pos.Ad_id
,pos.Pr_id
,pos.prog_id
,pos.port_id
,pos.o_type
,pos.o_id
,pos.s_id
,pos.c_id
,pos.s_type_id
,pos.s_type
,pos.e_date
,pos.mv
,0 is_pub
, 1 is_adj
,pos.is_unsup
,getdate() date
,getdate() timestamp
from #temp pos
left join acc c with(nolock) ON pos._id = c.c_id
AND pos.account_id = c.account_id
AND pos.Pr_id = c.pr_id
AND pos.prog_id = c.prog_id
AND pos.port_id = c.port_id
and pos.style_type_id=c.s_type_id
AND pos.s_id = c._id
AND pos.c_id = c.c_id
AND pos.s_type = c.s_type
AND pos.is_unsup = c.is_uns
AND pos.is_pub = 1
where c.a_id is null
union all
select pos.C_id
,pos.s_id
,pos.A_id
,pos.Ad_id
,pos.Pr_id
,pos.prog_id
,pos.port_id
,pos.o_type
,pos.o_id
,pos.s_id
,pos.c_id
,pos.s_type_id
,pos.s_type
,pos.e_date
,pos.mv
,0 is_pub
, 1 is_adj
,pos.is_unsup
,getdate() date
,getdate() timestamp
from #temp pos
left join acc c with(nolock) ON pos._id = c.c_id
AND pos.account_id = c.account_id
AND pos.s_id = c._id
AND pos.c_id = c.c_id
AND pos.s_type = c.s_type
AND pos.is_unsup = c.is_uns
AND pos.is_pub = 1
where c.a_id is null
AND pos.Pr_id is null AND c.pr_id is null
AND pos.prog_id is null AND c.prog_id is null
AND pos.port_id is null AND c.port_id is null
and pos.style_type_id is null AND c.s_type_id is null
我有一个需要很长时间才能完成的查询 运行。可能是因为我在连接条件中使用了太多isnulls
。如何通过删除 isnull
?
有没有不更新 table 的替代方法?查询如下:
select pos.C_id
,pos.s_id
,pos.A_id
,pos.Ad_id
,pos.Pr_id
,pos.prog_id
,pos.port_id
,pos.o_type
,pos.o_id
,pos.s_id
,pos.c_id
,pos.s_type_id
,pos.s_type
,pos.e_date
,pos.mv
,0 is_pub
, 1 is_adj
,pos.is_unsup
,getdate() date
,getdate() timestamp
from #temp pos
left join acc c with(nolock) ON pos._id = c.c_id
AND pos.account_id = c.account_id
AND isnull(pos.Pr_id,0) = isnull(c.pr_id,0)
AND isnull(pos.prog_id,0) = isnull(c.prog_id,0)
AND isnull(pos.port_id,0) = isnull(c.port_id,0)
and isnull(pos.style_type_id,0)=isnull(c.s_type_id,0)
AND pos.s_id = c._id
AND pos.c_id = c.c_id
AND pos.s_type = c.s_type
AND pos.is_unsup = c.is_uns
AND pos.is_pub = 1
where c.a_id is null
尝试使用
AND (pos.Pr_id = c.pr_id OR (pos.Pr_id IS NULL AND c.pr_id IS NULL))
而不是
AND ISNULL(pos.Pr_id,0) = ISNULL(c.pr_id,0)
IS NULL 比 ISNULL 更有效
您确实需要在临时 table #temp
上设置聚簇索引,如果不存在 sql-server 将为连接提供默认的 hash-based 索引,并且它对于大型 tables 来说性能不佳。
如果您在 #temp
table 中拥有的所有 id 列中的任何一个是唯一键,您确实需要在其上创建聚集索引:
CREATE CLUSTERED INDEX cx_temp ON #temp (YourIDColumn);
如果您在 #temp
中没有键列,请按以下方式为其添加身份主键:
1) 如果您使用 SELECT INTO
方法创建 #temp
,更改
select *
into #temp
from YourQuery
在
select IDENTITY (int, 1,1) ThisIsTheKey, *
into #temp
from YourQuery
-- and then add the index
CREATE CLUSTERED INDEX cx_temp ON #temp (ThisIsTheKey);
1) 如果您使用 CREATE TABLE
+ INSERT INTO
方法,只需像这样添加列:
CREATE TABLE #TEMP (
ThisIsTheKey INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
..
..
-- ALL YOUR OTHER COLUMNS
..
..
)
不要依赖覆盖非聚集索引,因为优化器可能不会使用它们,因为您选择的列太多。
首先测试聚簇索引,如果需要进一步优化可以尝试添加一些特定的非聚簇索引。
下面的查询呢
select pos.C_id
,pos.s_id
,pos.A_id
,pos.Ad_id
,pos.Pr_id
,pos.prog_id
,pos.port_id
,pos.o_type
,pos.o_id
,pos.s_id
,pos.c_id
,pos.s_type_id
,pos.s_type
,pos.e_date
,pos.mv
,0 is_pub
, 1 is_adj
,pos.is_unsup
,getdate() date
,getdate() timestamp
from #temp pos
left join acc c with(nolock) ON pos._id = c.c_id
AND pos.account_id = c.account_id
AND pos.Pr_id = c.pr_id
AND pos.prog_id = c.prog_id
AND pos.port_id = c.port_id
and pos.style_type_id=c.s_type_id
AND pos.s_id = c._id
AND pos.c_id = c.c_id
AND pos.s_type = c.s_type
AND pos.is_unsup = c.is_uns
AND pos.is_pub = 1
where c.a_id is null
union all
select pos.C_id
,pos.s_id
,pos.A_id
,pos.Ad_id
,pos.Pr_id
,pos.prog_id
,pos.port_id
,pos.o_type
,pos.o_id
,pos.s_id
,pos.c_id
,pos.s_type_id
,pos.s_type
,pos.e_date
,pos.mv
,0 is_pub
, 1 is_adj
,pos.is_unsup
,getdate() date
,getdate() timestamp
from #temp pos
left join acc c with(nolock) ON pos._id = c.c_id
AND pos.account_id = c.account_id
AND pos.s_id = c._id
AND pos.c_id = c.c_id
AND pos.s_type = c.s_type
AND pos.is_unsup = c.is_uns
AND pos.is_pub = 1
where c.a_id is null
AND pos.Pr_id is null AND c.pr_id is null
AND pos.prog_id is null AND c.prog_id is null
AND pos.port_id is null AND c.port_id is null
and pos.style_type_id is null AND c.s_type_id is null