Выбор из большой таблицы SQL 2005 - PullRequest
1 голос
/ 20 апреля 2010

У меня есть таблица SQL, в которой более 1000000 строк, и мне нужно выбрать запрос, как показано ниже:

   SELECT DISTINCT TOP (200) COUNT(1) AS COUNT,  KEYWORD
   FROM QUERIES WITH(NOLOCK)
   WHERE KEYWORD LIKE  '%Something%'
   GROUP BY KEYWORD ORDER BY 'COUNT' DESC

Не могли бы вы сказать мне, как я могу оптимизировать его, чтобы ускорить процесс выполнения? Спасибо за полезные ответы.

Ответы [ 6 ]

1 голос
/ 20 апреля 2010

Сначала я посмотрю на план выполнения, чтобы увидеть, как сервер sql пытается получить доступ к вашим данным. Здесь - ссылка только на одну из многих статей об анализе плана выполнения.

0 голосов
/ 20 апреля 2010

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

http://en.wikipedia.org/wiki/Inverted_index

0 голосов
/ 20 апреля 2010

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

Кроме того, результаты, которые вы получаете, могут быть неточными, если у вас есть ключевые слова, вложенные в другие (например, «корзина» будет соответствовать поиску по ключевому слову в «машине», а это не то, что вам нужно).

0 голосов
/ 20 апреля 2010

Задать вопрос о производительности SQL Server без предоставления схемы - пустая трата времени каждого. Я собираюсь ответить на другой вопрос, который вы должны были задать в первую очередь:

Какую схему мне использовать для эффективно удовлетворить запрос как SELECT DISTINCT TOP (200) COUNT(1) AS COUNT, KEYWORD FROM QUERIES WHERE KEYWORD LIKE '%Something%'GROUP BY KEYWORD ORDER BY 'COUNT' DESC когда таблица QUERIES имеет более 1М строк?

Правильная схема зависит от селективности KEYWORD. Один из возможных вариантов - нормализовать KEYWORD в таблице поиска и иметь узкий некластеризованный индекс для идентификатора поиска:

CREATE TABLE KEYWORDS (KeywordId INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
  Keyword VARCHAR(...) UNIQUE);
CREATE TABLE QUERIES (...,
  KeywordId INT NOT NULL,
  CONSTRAINT FK_KEYWORD 
   FOREIGN KEY KeywordId
   REFERENCES KEYWORDS (KeywordId),
  ...);
CREATE INDEX ndxQueriesKeyword ON Queries (KeywordId);

Если количество отдельных ключевых слов относительно мало, исходный запрос может быть быстро удовлетворен сканированием таблицы Keywqord, за которым следует сканирование диапазона непрямых циклов индекса ndxQueriesKeyword, которое очень узкое и поэтому генерирует низкий IO.

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

Вы можете рассмотреть возможность использования другого предложения WHERE, а именно одного LIKE 'Something%, которое является SARGable и может использовать индекс для KEYWORK, получая выгоду от сокращения диапазона и более узкого сканирования, чем полное сканирование таблицы.

Если вы используете Enterprise Edition, вы можете рассмотреть возможность добавления представления индексов с предварительно вычисленными агрегатами:

CREATE VIEW vwQueryKeywords 
WITH SCHEMABINDING
AS SELECT KEYWORD, COUNT_BIG(*) as COUNT
FROM dbo.QUERIES
GROUP BY KEYWORD;

CREATE CLUSTERED INDEX cdxQueryKeywords ON vwQueryKeywords(KEYWORD);

На EE оптимизатор будет рассматривать индексированное представление для исходного запроса. На не-EE вам придется изменить запрос для выполнения с представлением с подсказкой NOEXPAND:

SELECT KEYWORD, COUNT
FROM vwQueryKeywords WITH(NOEXPAND)
WHERE KEYWORD LIKE '%Something%';

Еще один совершенно другой подход - полностью отказаться от условия LIKE '%Something%' в пользу полнотекстового поиска:

SELECT DISTINCT TOP (200) COUNT(1) AS
 COUNT,  KEYWORD FROM QUERIES WHERE
 CONTAINS (Keyword, Something)
 GROUP BY
 KEYWORD ORDER BY 'COUNT' DESC

Поскольку поиск FT является поиском обратного индекса, он может оказаться оптимальным по сравнению с традиционным WHERE. Единственная проблема заключается в том, что вы сможете искать только полные слова, так как FT не позволит вам искать частичные совпадения, как это делает LIKE. Опять же, фактический пробег будет варьироваться в зависимости от профиля данных ключевого слова (т.е. его статистики и распределения).

0 голосов
/ 20 апреля 2010

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

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

В вашем конкретном случае узкое место наиболее вероятно в предложении WHERE. LIKE сравнения, как правило, неэффективны, особенно когда они окружены знаками процента, поскольку запрос не может использовать преимущества индексов столбца и т. Д. В зависимости от того, как вы сохранили данные, полнотекстовая индексация может быть полезной опцией, так как она часто превосходит LIKE '%SOMEVALUE%'.

0 голосов
/ 20 апреля 2010

Как сказал Джереми, вам нужно посмотреть на план выполнения и статистику клиента, чтобы увидеть, что быстрее. Тем не менее, пара предложений. Во-первых, действительно ли вам нужен префикс подстановки в вашем поиске? То есть, LIKE '%Something%' не сможет использовать индекс, тогда как LIKE 'Something%' будет. Во-вторых, вы можете попробовать CTE, чтобы увидеть, будет ли быстрее. Итак, что-то вроде:

;With NumberedItems As
    (
    Select Keyword, Count(*) As [Count]
        , ROW_NUMBER() OVER ( ORDER BY Keyword, Count(*) DESC ) As ItemRank
    From Queries WITH (NOLOCK)
    Where Keyword LIKE '%Something%'
    Group By Keyword
    )
Select Keyword, [Count]
From NumberedItems
Where ItemRank <= 200
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...