我最近一直在嗅探论坛和博客,但需要一些长时间运行查询的帮助。它是存储过程系统的一部分。这个指定的语句过去大约需要5分钟,但最近已经运行了72个小时!
以下是设置:
SQL Server 2005,内存为28GB。两个安装点到SAN,共享磁盘由10个主轴组成。数据位于一个挂载点上,另一个挂载数据空间上的tempdb。这个服务器上只有一个用户数据库。
这是两个表,condit
和condmod
。 Condit
包含800K记录,condmod
最初为空。为了测试目的,我在进程启动之前发出truncate mcmain.condmod。
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[DF__condit__con_notm__000AF8CF]') AND type = 'D')
BEGIN
ALTER TABLE [mcmain].[condit] DROP CONSTRAINT [DF__condit__con_notm__000AF8CF]
END
GO
/****** Object: Table [mcmain].[condit] Script Date: 02/07/2012 11:57:47 ******/
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[mcmain].[condit]') AND type in (N'U'))
DROP TABLE [mcmain].[condit]
GO
/****** Object: Table [mcmain].[condit] Script Date: 02/07/2012 11:57:49 ******/
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[mcmain].[condit]') AND type in (N'U'))
BEGIN
CREATE TABLE [mcmain].[condit](
[con_levgln] [char](13) NULL,
[con_stat] [char](4) NULL,
[con_dscgrp] [char](35) NULL,
[con_levart] [char](20) NULL,
[con_desc] [char](50) NULL,
[con_disc1] [numeric](5, 0) NULL,
[con_disc2] [numeric](5, 0) NULL,
[con_disc3] [numeric](5, 0) NULL,
[con_ntprce] [numeric](9, 0) NULL,
[con_dtstrt] [datetime] NULL,
[con_dtend] [datetime] NULL,
[con_volc] [char](8) NULL,
[con_updnmr] [char](20) NULL,
[con_notmod] [bit] NULL,
[con_ascver] [char](5) NULL,
[con_prddat] [datetime] NULL,
[con_cusgln] [char](13) NULL,
[con_cusdeb] [char](40) NULL,
[con_rowid] [int] IDENTITY(1,1) NOT NULL
) ON [PRIMARY]
END
GO
IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[DF__condit__con_notm__000AF8CF]') AND type = 'D')
BEGIN
ALTER TABLE [mcmain].[condit] ADD DEFAULT ((0)) FOR [con_notmod]
END
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[DF__condmod__com_not__7E22B05D]') AND type = 'D')
BEGIN
ALTER TABLE [mcmain].[condmod] DROP CONSTRAINT [DF__condmod__com_not__7E22B05D]
END
GO
/****** Object: Table [mcmain].[condmod] Script Date: 02/07/2012 11:57:56 ******/
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[mcmain].[condmod]') AND type in (N'U'))
DROP TABLE [mcmain].[condmod]
GO
/****** Object: Table [mcmain].[condmod] Script Date: 02/07/2012 11:57:58 ******/
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[mcmain].[condmod]') AND type in (N'U'))
BEGIN
CREATE TABLE [mcmain].[condmod](
[com_levgln] [char](13) NULL,
[com_stat] [char](4) NULL,
[com_dscgrp] [char](35) NULL,
[com_levart] [char](20) NULL,
[com_desc] [char](50) NULL,
[com_disc1] [numeric](5, 0) NULL,
[com_disc2] [numeric](5, 0) NULL,
[com_disc3] [numeric](5, 0) NULL,
[com_ntprce] [numeric](9, 0) NULL,
[com_dtstrt] [datetime] NULL,
[com_dtend] [datetime] NULL,
[com_volc] [char](8) NULL,
[com_updnmr] [char](20) NULL,
[com_notmod] [bit] NULL,
[com_ascver] [char](8) NULL,
[com_prddat] [datetime] NULL,
[com_cusgln] [char](13) NULL,
[com_cusdeb] [char](40) NULL,
[com_rowid] [int] IDENTITY(1,1) NOT NULL
) ON [PRIMARY]
END
GO
IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[DF__condmod__com_not__7E22B05D]') AND type = 'D')
BEGIN
ALTER TABLE [mcmain].[condmod] ADD DEFAULT ((0)) FOR [com_notmod]
END
GO
以下是长时间运行的隔离代码:
DECLARE @TempIdTable TABLE ([com_rowid] Int PRIMARY KEY)
INSERT @TempIdTable([com_rowid])
SELECT cmd.[com_rowid]
FROM [mcmain].[condmod] AS cmd
LEFT OUTER JOIN [mcmain].[condit] AS cdt
ON con_levgln = com_levgln
AND IsNull(con_dscgrp,'') = IsNull(com_dscgrp,'')
AND IsNull(con_levart,'') = IsNull(com_levart,'')
AND IsNull(con_volc,'') = IsNull(com_volc,'')
AND IsNull(con_cusgln,'') = IsNull(com_cusgln,'')
AND IsNull(con_cusdeb,'') = IsNull(com_cusdeb,'')
WHERE con_levgln is NULL
--select * from @TempIdTable
INSERT INTO mcmain.condit(con_levgln
,con_stat
,con_dscgrp
,con_levart
,con_desc
,con_disc1
,con_disc2
,con_disc3
,con_ntprce
,con_dtstrt
,con_dtend
,con_volc
,con_notmod
,con_updnmr
,con_ascver
,con_cusgln
,con_cusdeb)
SELECT com_levgln
,com_stat
,com_dscgrp
,com_levart
,com_desc
,com_disc1
,com_disc2
,com_disc3
,com_ntprce
,com_dtstrt
,com_dtend
,com_volc
,com_notmod
,com_updnmr
,com_ascver
,com_cusgln
,com_cusdeb
FROM [mcmain].[condmod] AS cmd
INNER JOIN @TempIdTable AS tit
ON tit.com_rowid = cmd.com_rowid
插入@TempIdTable
需要永远。我该怎么做才能加快这个过程?
TIA
Cees Cappelle
P.S。我在两个表上都有聚簇索引,例如:
/****** Object: Index [condmodTest] Script Date: 02/07/2012 13:24:34 ******/
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[mcmain].[condmod]') AND name = N'condmodTest')
CREATE CLUSTERED INDEX [condmodTest] ON [mcmain].[condmod]
(
[com_levgln] ASC,
[com_dscgrp] ASC,
[com_levart] ASC,
[com_volc] ASC,
[com_cusgln] ASC,
[com_cusdeb] 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]
GO
如果我直接选择(刚才),则需要2秒钟。
以下是代码:
SELECT com_levgln
,com_stat
,com_dscgrp
,com_levart
,com_desc
,com_disc1
,com_disc2
,com_disc3
,com_ntprce
,com_dtstrt
,com_dtend
,com_volc
,com_notmod
,com_updnmr
,com_ascver
,com_cusgln
,com_cusdeb
FROM mcmain.condmod
LEFT OUTER JOIN mcmain.condit
ON con_levgln = com_levgln
AND IsNull(con_dscgrp,'') = IsNull(com_dscgrp,'')
AND IsNull(con_levart,'') = IsNull(com_levart,'')
AND IsNull(con_volc,'') = IsNull(com_volc,'')
AND IsNull(con_cusgln,'') = IsNull(com_cusgln,'')
AND IsNull(con_cusdeb,'') = IsNull(com_cusdeb,'')
WHERE con_levgln is NULL
我刚刚使用以下代码执行了Actial Execution计划。花了3'16''???
truncate table mcmain.condit
CREATE TABLE #TempIdTable ([com_rowid] Int PRIMARY KEY)
-- DECLARE @TempIdTable TABLE
-- ([com_rowid] Int PRIMARY KEY)
INSERT #TempIdTable
([com_rowid])
SELECT cmd.[com_rowid]
FROM [mcmain].[condmod] AS cmd
LEFT OUTER JOIN [mcmain].[condit] AS cdt
ON con_levgln = com_levgln
AND IsNull(con_dscgrp,'') = IsNull(com_dscgrp,'')
AND IsNull(con_levart,'') = IsNull(com_levart,'')
AND IsNull(con_volc,'') = IsNull(com_volc,'')
AND IsNull(con_cusgln,'') = IsNull(com_cusgln,'')
AND IsNull(con_cusdeb,'') = IsNull(com_cusdeb,'')
WHERE con_levgln is NULL
-- AND com_updnmr = @plannummer
INSERT INTO mcmain.condit
(con_levgln
,con_stat
,con_dscgrp
,con_levart
,con_desc
,con_disc1
,con_disc2
,con_disc3
,con_ntprce
,con_dtstrt
,con_dtend
,con_volc
,con_notmod
,con_updnmr
,con_ascver
,con_cusgln
,con_cusdeb)
SELECT com_levgln
,com_stat
,com_dscgrp
,com_levart
,com_desc
,com_disc1
,com_disc2
,com_disc3
,com_ntprce
,com_dtstrt
,com_dtend
,com_volc
,com_notmod
,com_updnmr
,com_ascver
,com_cusgln
,com_cusdeb
FROM [mcmain].[condmod] AS cmd
INNER JOIN #TempIdTable AS tit
ON tit.com_rowid = cmd.com_rowid
相同的陈述,但使用tablevariable花了1'39''
当我运行sp时,同样的语句需要数小时和数小时。仍然没有得到它。
答案 0 :(得分:5)
如果SELECT
本身需要很长时间
您可以考虑使用NOT EXISTS
而不是OUTER JOIN ... NULL
,因为这通常更有效。
另外,我会摆脱不可比较的ISNULL
比较。
SELECT cmd.[com_rowid]
FROM [mcmain].[condmod] AS cmd
WHERE NOT EXISTS (SELECT *
FROM [mcmain].[condit] AS cdt
WHERE con_levgln = com_levgln
AND EXISTS (SELECT con_dscgrp,
con_levart,
con_volc,
con_cusgln,
con_cusdeb
INTERSECT
SELECT com_dscgrp,
com_levart,
com_volc,
com_cusgln,
com_cusdeb))
如果SELECT
自行运行得非常快,但是在插入表变量时却没有,那么检查一下你是否得到一个并行计划。
插入表变量的查询不会并行化,因此如果这是您可以考虑更改为#temp
表的问题。
如果这些建议都没有帮助,那么我建议您在此过程运行时开始监视等待类型。请参阅论文"SQL Server 2005 Waits and Queues"
答案 1 :(得分:0)
注意:使用@tables使用tempdb。
你应该尝试增加临时数据库文件的数量...你可以从tempdb文件的数量开始,等于你拥有的触发器的数量......但作为一个好的起点,只需跳到10 ......您可能遇到的问题是对tempdb文件的争用。你应该在tempdb中寻找页面锁存。
本文讨论了我上面所写的泛化是一种误解(但不一定是错误的),但这样做可以很好地解释这个问题。它还指向其他文章,提供有关如何查找页面锁定的信息。
A SQL Server DBA myth a day: (12/30) tempdb should always have one data file per processor core