Оптимизировать SQL-запрос, который использует NOT EXISTS с большим количеством столбцов в несуществующем предложении WHERE - PullRequest
0 голосов
/ 06 января 2010

Редактировать: с использованием SQL Server 2005.

У меня есть запрос, который должен проверить, были ли строки из устаревшей базы данных уже импортированы в новую базу данных, и импортировать их, если их еще нет. Поскольку унаследованная база данных была плохо спроектирована, для строк из унаследованной таблицы не существует уникального идентификатора, поэтому я должен использовать эвристику, чтобы решить, была ли строка импортирована. (У меня нет контроля над устаревшей базой данных.) Новая база данных имеет немного иную структуру, и мне нужно проверить несколько значений, таких как совпадение дат создания, совпадение номера группы и т. Д., Чтобы эвристически решить, существует ли строка в новой базе данных или не. Не очень красиво, но плохой дизайн устаревшей системы, с которой она должна взаимодействовать, оставляет мне небольшой выбор.

Так или иначе, пользователи системы начали выбрасывать в систему от 10 до 100 раз больше данных, чем я планировал, и теперь запрос выполняется слишком медленно. Можете ли вы предложить способ сделать это быстрее? Вот код с некоторыми изменениями для конфиденциальности или упрощения, но я думаю, что оставил важную часть:

INSERT INTO [...NewDatabase...]
SELECT [...Bunch of columns...]
  FROM  [...OldDatabase...] AS t1
 WHERE t1.Printed = 0
  AND NOT EXISTS(SELECT *
                   FROM [...New Database...] AS s3
                  WHERE year(s3.dtDatePrinted) = 1850  --This allows for re-importing rows marked for reprint
                    AND CAST(t1.[Group] AS int) = CAST(s3.vcGroupNum AS int)
                    AND RTRIM(t1.Subgroup) = s3.vcSubGroupNum
                    AND RTRIM(t1.SSN) = s3.vcPrimarySSN
                    AND RTRIM(t1.FirstName) = s3.vcFirstName
                    AND RTRIM(t1.LastName) = s3.vcLastName
                    AND t1.CaptureDate = s3.dtDateCreated)

Ответы [ 2 ]

2 голосов
/ 06 января 2010

Не зная, как выглядит схема, ваш первый шаг к EXPLAIN этим подзапросам.Это должно показать вам, где база данных тратит время.Если индексов нет, вероятно, выполняется многократное сканирование всей таблицы.Если бы мне пришлось угадывать, я бы сказал, что t1.printed и s3.dtDatePrinted являются двумя наиболее важными для индексации, поскольку они отсеивают то, что уже было конвертировано.

Также все, что нужно вычислить, можетзаставить базу данных не использовать индекс.Например, звонки на номера RTRIM и CAST.Это говорит о том, что у вас есть грязные данные в новой базе данных.Обрежьте его навсегда, и посмотрите, как изменить t1.group на правильный тип.

year(s3.dtDatePrinted) = 1850 может обмануть оптимизатор, заставив его не использовать индекс для s3.dtDatePrinted (EXPLAIN должна сообщить вам об этом).Похоже, это просто флаг, установленный вами, чтобы проверить, была ли строка уже преобразована, поэтому установите для нее определенную дату (например, 1850-01-01 00:00:00) и выполните конкретное совпадение (т.е.. s3.dtDatePrinted = "1850-01-01 00:00:00") и теперь это простой поиск по индексу.

Упрощение сравнения также поможет.По сути, здесь имеется отношение 1 к 1 между t1 и s3 (если t1 - настоящее имя новой таблицы, рассмотрим что-то более описательное).Таким образом, вместо того, чтобы сопоставлять каждый отдельный бит s3 с t1, просто задайте столбцу t1 ссылку на первичный ключ соответствующей строки s3.Тогда вам просто нужно проверить одну вещь.Если вы не можете изменить t1, вы можете использовать третью таблицу для отслеживания отображений t1 в s3.

После того, как вы это сделаете, все, что вам нужно сделать, это объединить, чтобы найти строки в s3, которые не находятся вt1.

SELECT s3.*
FROM s3
LEFT JOIN t1 ON t1.s3 = s3.id   -- or whatever s3's primary key is
WHERE t1.s3 IS NULL
0 голосов
/ 06 января 2010

Попробуйте заменить это:

год (s3.dtDatePrinted) = 1850

С этим:

s3.dtDatePrinted> = '1850-01-01' и s3.dtDatePrinted <'1851-01-01' </p>

В этом случае, и при наличии индекса на dtDatePrinted МОЖЕТ, оптимизатор может использовать сканирование индекса диапазона.

Но я согласен с предыдущими постерами, что вам следует избегать RTRIM. Одна из идей заключается в том, чтобы сохранить в s3 нетривированное (оригинальное) значение или создать промежуточную таблицу, которая отображает нетривированные (новые) значения. Или даже создание материализованных взглядов. Но вся эта работа бесполезна без правильных указателей.

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