SQL Server 2005上长时间运行的INSERT查询

时间:2012-02-07 12:25:01

标签: sql-server-2005 tsql

我最近一直在嗅探论坛和博客,但需要一些长时间运行查询的帮助。它是存储过程系统的一部分。这个指定的语句过去大约需要5分钟,但最近已经运行了72个小时!

以下是设置:

SQL Server 2005,内存为28GB。两个安装点到SAN,共享磁盘由10个主轴组成。数据位于一个挂载点上,另一个挂载数据空间上的tempdb。这个服务器上只有一个用户数据库。

这是两个表,conditcondmodCondit包含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时,同样的语句需要数小时和数小时。仍然没有得到它。

2 个答案:

答案 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