Длительный запрос INSERT на SQL Server 2005 - PullRequest
4 голосов
/ 07 февраля 2012

В последнее время я выискиваю форумы и блоги, но мне нужна помощь с длинным запросом. Это часть системы хранимых процедур. Этот указанный оператор выполнялся примерно за 5 минут, но в последнее время он выполнялся до 72 часов!

Вот настройки:

SQL Server 2005 с 28 ГБ памяти. Две точки монтирования в SAN с общими дисками, состоящими из 10 шпинделей. Данные находятся в одной точке монтирования, войдите в другую, в базе данных tempdb. Всего одна база данных на этом сервере.

Вот две таблицы, condit и condmod. Condit содержит 800 тыс. Записей, condmod изначально пусто. Я запускаю усечение 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 занимает вечность. Что я могу сделать, чтобы ускорить этот процесс?

1020 * ТИА *

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

То же утверждение, но с использованием табличной переменной заняло 1'39 ''

Когда я запускаю sp, то же утверждение занимает часы и часы. Все еще не понимаю.

Ответы [ 2 ]

5 голосов
/ 07 февраля 2012

Если само SELECT занимает много времени

Вы можете рассмотреть возможность использования NOT EXISTS вместо OUTER JOIN ... NULL, поскольку это часто более эффективно.

Также я бы избавился от* sargable 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»

0 голосов
/ 07 февраля 2012

Примечание: использование @tables использует базу данных tempdb.

Вы должны попытаться увеличить количество файлов temp db ... вы можете начать с количества файлов tempdb, равногоколичество процедур у вас есть ... но в качестве хорошей отправной точки просто перейдите к 10 ... Проблема, с которой вы можете столкнуться, - это конфликт за файлы tempdb.Вы должны искать блокировку страницы в базе данных tempdb.

В этой статье обсуждается, как обобщение, которое я написал выше, является неправильным (но не обязательно ошибочным), но при этом хорошо объясняет проблему.Он также указывает на другие статьи, в которых содержится информация о том, как искать блокировку страниц.

Миф о администраторах баз данных SQL Server в день: (12/30) база данных tempdb всегда должна иметь один файл данных на ядро ​​процессора

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...