Массивное CROSS JOIN в SQL Server 2005 - PullRequest
2 голосов
/ 10 декабря 2008

Я портирую процесс, который создает MASSIVE CROSS JOIN из двух таблиц. Результирующая таблица содержит 15 м записей (похоже, что процесс выполняет 30-миллиметровое перекрестное соединение с таблицей 2600 строк и таблицей 12000 строк, а затем выполняет некоторую группировку, которая должна разбить ее пополам). Ряды относительно узкие - всего 6 столбцов. Он работает в течение 5 часов без каких-либо признаков завершения. Я только что заметил расхождение в подсчете между известным товаром и тем, что я ожидал бы для перекрестного соединения, поэтому в моих выходных данных нет группировки или дедупликации, которые бы делили финальный стол пополам - но все равно кажется, что он не завершит скоро.

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

Но, учитывая, что существующий процесс делает это (за меньшее время на менее мощной машине, использующей язык FOCUS), есть ли варианты для повышения производительности больших CROSS JOIN с в 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

Таким образом, требуемый вывод - это CROSS JOIN (он соединяет пустой столбец с каждой стороны).

В 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 (бу-ху), поэтому я не могу сказать, лучше или хуже план, который он использует, после изменения индексов. Я еще не реорганизовал его, но ожидаю, что весь стол скоро исчезнет.

Ответы [ 3 ]

2 голосов
/ 10 декабря 2008

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

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? Как насчет индексов? При такой большой вставке вы захотите удалить все триггеры и индексы в этой таблице.

2 голосов
/ 10 декабря 2008

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

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

1 голос
/ 10 декабря 2008

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


   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

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

...