Производительность сопоставления строк T-SQL и подстановочных знаков в большой таблице - PullRequest
3 голосов
/ 11 июля 2011

У меня есть небольшая проблема с T-SQL, я в основном нахожусь в состоянии, когда мне нужно выполнить целую кучу запросов, таких как:

SELECT TOP 30 * FROM [table]
    WHERE firstfield IS NOT NULL
    AND secondfield IS NOT NULL
    AND (firstfield LIKE '%substring%' OR secondfield LIKE '%substring%')

Это выполняется из программы на C # .NET с таймаутом на SqlCommand, установленным на 90 секунд, и для большинства запросов (которые ищут редкие или несуществующие термины) он достигает тайм-аута.

Проблема с этим, конечно, в том, что он очень медленный, но данные нужно выбирать. После выборки все возвращенные значения firstfield и secondfield просто объединяются (эта более крупная строка сохраняется и анализируется программой).

В настоящее время я запускаю это на своем рабочем ноутбуке, поскольку рабочий сервер, на котором эти данные слишком сильно замедляется, при выполнении тысяч таких запросов. При работе на рабочем сервере я получаю результаты примерно в 30% случаев, а на моем ноутбуке (с 4 ГБ ОЗУ и обычным 2,5-дюймовым жестким диском с вращающейся ржавчиной) он приближается к 10%.

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

CREATE TABLE(
    id INT NOT NULL PRIMARY KEY IDENTITY,
    keyword VARCHAR(255) NOT NULL,
    returneddata VARCHAR(MAX), -- Or possibly a TEXT field.
)

Таким образом, я мог оставить запущенную программу считывателя и просто сделать так, чтобы моя основная программа запросила эту таблицу. Но, честно говоря, я бы предпочел просто найти способ заставить запросы выполняться быстрее (или другой способ выполнения запросов). Я просто очень надеюсь, что я дурачок и что я упустил какой-то очевидный способ сделать это быстрее ...

Ответы [ 5 ]

4 голосов
/ 11 июля 2011

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

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

В качестве альтернативы можно создать два индекса: один на (первое поле), другой на (второе поле) и разделитьВаш запрос состоит из двух запросов: один, который запрашивает только первое поле, другой - только второе.

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

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

3 голосов
/ 11 июля 2011

Вы можете включить полный текст, а затем использовать в своем запросе свободный текст вместо подстановочного знака http://msdn.microsoft.com/en-us/library/ms176078.aspx

2 голосов
/ 11 июля 2011

Если по обеим сторонам строки есть подстановочный знак (например, %x%, а не просто x%), то SQL Server не может использовать статистику для оптимизации запроса.

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

1 голос
/ 11 июля 2011

Я бы настоятельно рекомендовал использовать подход второй таблицы.

Вы можете запустить программу «fetcher» как фоновую задачу / всю ночь и т. Д.

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

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

В конце концов, ваши пользователи оценят более быстрое время отклика.

0 голосов
/ 11 июля 2011

Поскольку оба поля varchar(800), вы можете сделать следующее:

SELECT TOP 30 * FROM [table]
    WHERE (
        coalesce(firstfield, '') LIKE '%substring%' OR
        coalesce(secondfield, '') LIKE '%substring%')

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

...