Лучший запрос SQL для списка записей, содержащих определенные символы? - PullRequest
2 голосов
/ 29 июня 2011

В настоящее время я работаю с относительно большой базой данных SQL Server 2000.Он имеет размер 80 ГБ и содержит миллионы и миллионы записей.

Мне нужно вернуть список имен, который содержит хотя бы один из ряда недопустимых символов.Под недопустимыми символами подразумевается произвольный список символов, который определяется заказчиком.В приведенном ниже примере я использую вопросительный знак, точку с запятой, точку и запятую в качестве списка недопустимых символов.

Сначала я хотел создать функцию CLR, которая работала бы с регулярными выражениями, но в качестве SQL Server 2000,Я думаю, что это не может быть и речи.

На данный момент я сделал так:

select x from users
where 
columnToBeSearched like '%?%' OR
columnToBeSearched like '%;%' OR
columnToBeSearched like '%.%' OR
columnToBeSearched like '%,%' OR
otherColumnToBeSearched like '%?%' OR
otherColumnToBeSearched like '%;%' OR
otherColumnToBeSearched like '%.%' OR
otherColumnToBeSearched like '%,%'

Теперь я ни в коем случае не эксперт по SQL, но у меня такое ощущение, что приведенный выше запрос будет оченьнеэффективен.Выполнение 8 множественных поисков по шаблону в таблице с миллионами записей, похоже, может серьезно замедлить работу системы.Хотя на тестовых серверах это работает нормально, я чувствую, что «это должно быть совершенно неправильно».

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

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

Может кто-нибудь сказать мне, как лучше всего достичь моего результата?Спасибо!

/ Мортен

Ответы [ 4 ]

6 голосов
/ 29 июня 2011

Он мало используется, но оператор LIKE принимает шаблоны аналогичным (но значительно упрощенным) способом с Regex. Эта ссылка является страницей MSDN для него.

В вашем случае вы можете упростить до (не проверено):

select x from users
where 
    columnToBeSearched like '%[?;.,]%' OR
    otherColumnToBeSearched like '%[?;.,]%'

Также обратите внимание, что вы можете создать шаблон LIKE как переменную, позволяющую клиенту определить часть ваших требований.

Еще одна важная оптимизация: если у вас есть обновленная дата (или метка времени) в строке пользователя (для любого типа истории аудита), вы всегда можете просто запросить строки, обновленные с момента последней проверки.

3 голосов
/ 29 июня 2011

Если этот запрос будет выполняться неоднократно, вам, вероятно, лучше создать индекс для него.Синтаксис ускользает от меня на данный момент, но вы, вероятно, могли бы создать вычисляемый столбец (edit: вероятно, PERSISTED вычисляемый столбец), который равен 1, если columnToBeSearched или otherColumnToBeSearched содержат недопустимые символы, и 0 в противном случае.Создайте индекс для этого столбца и просто выберите все строки, где столбец равен 1. Это предполагает, что набор недопустимых символов является фиксированным для этой установки базы данных (я предполагаю, что это то, что вы подразумеваете под «указанным клиентом»).Если, с другой стороны, в каждом запросе может быть указан другой набор недопустимых символов, это не сработает.

Кстати, если вы не возражаете против риска чтения незафиксированных строк, вы можете запуститьзапрос в транзакции с уровнем изоляции READ UNCOMMITTED, чтобы не блокировать другие транзакции.

0 голосов
/ 29 июня 2011

Посмотрите на PATINDEX, это позволяет вам помещать в массив символов PATINDEX ('[._]', ColumnName) возвращает 0 или значение первого вхождения недопустимого символа, найденного в определенном значении. Надеюсь, это поможет.

0 голосов
/ 29 июня 2011

Вы можете попытаться разделить ваши данные по горизонтали и «разбить» ваш запрос на несколько небольших запросов. Например, вы можете сделать

SELECT x FROM users 
WHERE users.ID BETWEEN 1 AND 5000 
AND -- your filters on columnToBeSearched

Объединение результатов в одном списке может быть немного неудобно, но если это отчет, который вы извлекаете только один раз (или время от времени), это может быть осуществимо. Я предполагаю, что ID - это первичный ключ пользователей или столбец с определенным индексом, что означает, что SQL должен быть в состоянии создать эффективный план выполнения, в котором он оценивает пользователей. ID между 1 и 5000 (быстро) перед попыткой проверки фильтры (которые могут быть медленными).

...