Вопрос

Я портирую процесс, который создает ОГРОМНУЮ CROSS JOIN из двух столов.Результирующая таблица содержит 15 миллионов записей (похоже, что процесс выполняет перекрестное соединение длиной 30 метров с таблицей из 2600 строк и таблицей из 12 000 строк, а затем выполняет некоторую группировку, которая должна разделить ее пополам).Строки относительно узкие – всего 6 столбцов.Он работает уже 5 часов без каких-либо признаков завершения.Я только что заметил несоответствие в подсчете между известным хорошим и тем, что я ожидал бы от перекрестного соединения, поэтому в моем выводе нет группировки или дедупликации, которые сократили бы итоговую таблицу вдвое, но все равно кажется, что это не приведет ни к какому результату. скоро время.

Сначала я постараюсь исключить эту таблицу из процесса, если это вообще возможно - очевидно, ее можно заменить объединением с обеими таблицами по отдельности, но сейчас я не могу видеть, где еще она используется.

Но учитывая, что существующий процесс это делает (за меньшее время, на менее мощной машине, с использованием языка FOCUS), есть ли варианты повышения производительности больших CROSS JOINs в SQL Server (2005) (аппаратное обеспечение на самом деле не вариант, это 64-битная 8-процессорная система с 32 ГБ ОЗУ)?

Подробности:

В FOCUS это написано так (я пытаюсь получить тот же результат, который представляет собой CROSS JOIN в SQL):

JOIN CLEAR *
DEFINE FILE COSTCENT
  WBLANK/A1 = ' ';
  END
TABLE FILE COSTCENT
  BY WBLANK BY CC_COSTCENT
  ON TABLE HOLD AS TEMPCC FORMAT FOCUS
  END

DEFINE FILE JOINGLAC
  WBLANK/A1 = ' ';
  END
TABLE FILE JOINGLAC
  BY WBLANK BY ACCOUNT_NO BY LI_LNTM
  ON TABLE HOLD AS TEMPAC FORMAT FOCUS INDEX WBLANK

JOIN CLEAR *
JOIN WBLANK IN TEMPCC TO ALL WBLANK IN TEMPAC
DEFINE FILE TEMPCC
  CA_JCCAC/A16=EDIT(CC_COSTCENT)|EDIT(ACCOUNT_NO);
  END
TABLE FILE TEMPCC
  BY CA_JCCAC BY CC_COSTCENT AS COST CENTER BY ACCOUNT_NO
  BY LI_LNTM
  ON TABLE HOLD AS TEMPCCAC
  END

Таким образом, требуемый результат на самом деле представляет собой ПЕРЕКРЕСТНОЕ СОЕДИНЕНИЕ (оно объединяет пустой столбец с каждой стороны).

В SQL:

CREATE TABLE [COSTCENT](
       [COST_CTR_NUM] [int] NOT NULL,
       [CC_CNM] [varchar](40) NULL,
       [CC_DEPT] [varchar](7) NULL,
       [CC_ALSRC] [varchar](6) NULL,
       [CC_HIER_CODE] [varchar](20) NULL,
 CONSTRAINT [PK_LOOKUP_GL_COST_CTR] PRIMARY KEY NONCLUSTERED
(
       [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY
= OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [JOINGLAC](
       [ACCOUNT_NO] [int] NULL,
       [LI_LNTM] [int] NULL,
       [PR_PRODUCT] [varchar](5) NULL,
       [PR_GROUP] [varchar](1) NULL,
       [AC_NAME_LONG] [varchar](40) NULL,
       [LI_NM_LONG] [varchar](30) NULL,
       [LI_INC] [int] NULL,
       [LI_MULT] [int] NULL,
       [LI_ANLZ] [int] NULL,
       [LI_TYPE] [varchar](2) NULL,
       [PR_SORT] [varchar](2) NULL,
       [PR_NM] [varchar](26) NULL,
       [PZ_SORT] [varchar](2) NULL,
       [PZNAME] [varchar](26) NULL,
       [WANLZ] [varchar](3) NULL,
       [OPMLNTM] [int] NULL,
       [PS_GROUP] [varchar](5) NULL,
       [PS_SORT] [varchar](2) NULL,
       [PS_NAME] [varchar](26) NULL,
       [PT_GROUP] [varchar](5) NULL,
       [PT_SORT] [varchar](2) NULL,
       [PT_NAME] [varchar](26) NULL
) ON [PRIMARY]

CREATE TABLE [JOINCCAC](
       [CA_JCCAC] [varchar](16) NOT NULL,
       [CA_COSTCENT] [int] NOT NULL,
       [CA_GLACCOUNT] [int] NOT NULL,
       [CA_LNTM] [int] NOT NULL,
       [CA_UNIT] [varchar](6) NOT NULL,
 CONSTRAINT [PK_JOINCCAC_KNOWN_GOOD] PRIMARY KEY CLUSTERED
(
       [CA_JCCAC] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY
= OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

С кодом SQL:

INSERT  INTO [JOINCCAC]
       (
        [CA_JCCAC]
       ,[CA_COSTCENT]
       ,[CA_GLACCOUNT]
       ,[CA_LNTM]
       ,[CA_UNIT]
       )
       SELECT  Util.PADLEFT(CONVERT(varchar, CC.COST_CTR_NUM), '0',
                                     7)
               + Util.PADLEFT(CONVERT(varchar, GL.ACCOUNT_NO), '0',
                                       9) AS CC_JCCAC
              ,CC.COST_CTR_NUM AS CA_COSTCENT
              ,GL.ACCOUNT_NO % 900000000 AS CA_GLACCOUNT
              ,GL.LI_LNTM AS CA_LNTM
              ,udf_BUPDEF(GL.ACCOUNT_NO, CC.COST_CTR_NUM, GL.LI_LNTM, 'N') AS CA_UNIT
       FROM   JOINGLAC AS GL
       CROSS JOIN COSTCENT AS CC

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

Я также подумываю о том, чтобы исключить UDF и манипуляции со строками и сначала выполнить CROSS JOIN, чтобы немного разбить процесс.

РЕЗУЛЬТАТЫ НА ПОКА:

Оказывается, UDF действительно вносят большой (отрицательный) вклад в производительность.Но также существует большая разница между перекрестным соединением 15-метрового ряда и перекрестным соединением 30-метрового ряда.У меня нет прав SHOWPLAN (угу), поэтому я не могу сказать, стал ли используемый им план лучше или хуже после изменения индексов.Я еще не проводил рефакторинг, но ожидаю, что вся таблица вскоре исчезнет.

Это было полезно?

Решение

Анализ этого запроса показывает, что из одной таблицы используется только один столбец, а из другой таблицы — только два столбца.Из-за очень небольшого количества используемых столбцов этот запрос можно легко расширить за счет покрывающих индексов:

CREATE INDEX COSTCENTCoverCross ON COSTCENT(COST_CTR_NUM)
CREATE INDEX JOINGLACCoverCross ON JOINGLAC(ACCOUNT_NO, LI_LNTM)

Вот мои вопросы по дальнейшей оптимизации:

Когда вы поместите запрос в анализатор запросов и нажмете кнопку «показать предполагаемый план выполнения», он покажет графическое представление того, что он собирается сделать.

Тип присоединения:Там должно быть соединение вложенного цикла.(другие варианты — соединение слиянием и хэш-соединение).Если вы видите вложенный цикл, то ок.Если вы видите объединение слиянием или хэш-соединение, сообщите нам об этом.

Порядок доступа к таблице:Поднимитесь до самого верха и прокрутите до конца вправо.Первым шагом должен быть доступ к таблице.Что это за таблица и какой метод используется (сканирование индекса, сканирование кластерного индекса)?Какой метод используется для доступа к другой таблице?

Параллелизм:Почти на всех значках плана вы должны увидеть маленькие зубчатые стрелки, указывающие на использование параллелизма.Если вы этого не видите, значит, это серьезная проблема!

Меня беспокоит этот udf_BUPDEF.Читает ли он из дополнительных таблиц?Util.PADLEFT меня беспокоит меньше, но всё же..что это такое?Если это не объект базы данных, рассмотрите возможность использования этого:

RIGHT('z00000000000000000000000000' + columnName, 7)

Есть ли триггеры на JOINCCAC?Как насчет индексов?При такой большой вставке вам захочется удалить все триггеры и индексы в этой таблице.

Другие советы

Продолжая высказывание других, функции БД, содержащие запросы, используемые при выборе, всегда делали мои запросы чрезвычайно медленными.Я сразу понял, что запрос был выполнен за 45 секунд, затем я удалил функцию, а результат составил 0 секунд :)

Поэтому проверьте, что udf_BUPDEF не выполняет никаких запросов.

Разбейте запрос, чтобы сделать его простым перекрестным соединением.


   SELECT  CC.COST_CTR_NUM, GL.ACCOUNT_NO
              ,CC.COST_CTR_NUM AS CA_COSTCENT
              ,GL.ACCOUNT_NO AS CA_GLACCOUNT
              ,GL.LI_LNTM AS CA_LNTM
-- I don't know what is BUPDEF doing? but remove it from the query for time being
--              ,udf_BUPDEF(GL.ACCOUNT_NO, CC.COST_CTR_NUM, GL.LI_LNTM, 'N') AS CA_UNIT
       FROM   JOINGLAC AS GL
       CROSS JOIN COSTCENT AS CC

Посмотрите, насколько хорошо простое перекрестное соединение?(без применения каких-либо функций)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top