Запланируйте кэширование и производительность плана - PullRequest
2 голосов
/ 19 июня 2010

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

BACKSTORY

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

Когда я ввожу запрос, подобный этому "ma br", он создаст этот SQL

SELECT EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p0
INTERSECT
SELECT EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p1
--@p0 String --'ma%'
--@p1 String --'br%'

Для каждого поискового запроса есть еще INTERSECT и SELECT

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

Что немного раздражает, так это то, что обычно выполнение первого запроса определенного ранга занимает намного больше времени.Бьюсь об заклад, это потому, что оптимизатор запросов переоценивает план выполнения.Но как мне быть с этим?Чем больше запросов я запускаю к ​​серверу, тем меньше он останавливается, но каждый другой запрос длится примерно 2-3 секунды.Это не имеет большого значения, но иногда это намного дольше, и я просто не вижу, откуда это происходит и как с этим бороться.Это должно быть молниеносно.

РЕДАКТИРОВАТЬ

Схема выглядит следующим образом:

CREATE TABLE InvertedIndex (
    Term varchar(255) NOT NULL,
    Ordinal tinyint NOT NULL,
    EntityType tinyint NOT NULL,
    EntityID int NOT NULL
)

Два индекса:

CREATE NONCLUSTERED INDEX IX_InvertedIndex ON InvertedIndex (Term) 
INCLUDE (Ordinal, EntityType, EntityID)

CREATE NONCLUSTERED INDEX IX_InvertedIndex_Reverse ON InvertedIndex (EntityType, EntityID) 

Этот материал остается, что происходит, когда операции вставки и удаления выполняются, когда индекс (InvertedIndex) должен быть обновлен и когда-либо полностью перестроен, повлияет ли это на использование QUERY PLAN?

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

WITH Search AS (
    SELECT EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p0
    INTERSECT
    SELECT EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p1
    INTERSECT
    SELECT EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p2
)
SELECT p.PersonID
, p.FullName
, p.Email
, p.MobilePhone
, p.HomeAddress
, p.HomeCity
FROM Search AS s
INNER JOIN Person AS p ON p.PersonID = s.EntityID AND s.EntityType = @pPersonEntityType
ORDER BY (CASE WHEN @p3 IN (SELECT Ordinal FROM InvertedIndex WHERE Term LIKE @p0 AND EntityID = s.EntityID AND EntityType = s.EntityType) THEN 0 ELSE 1 END) + (CASE WHEN @p4 IN (SELECT Ordinal FROM InvertedIndex WHERE Term LIKE @p1 AND EntityID = s.EntityID AND EntityType = s.EntityType) THEN 0 ELSE 1 END) + (CASE WHEN @p5 IN (SELECT Ordinal FROM InvertedIndex WHERE Term LIKE @p2 AND EntityID = s.EntityID AND EntityType = s.EntityType) THEN 0 ELSE 1 END)
@p0 String --'ma%'
@p1 String --'br%'
@p2 String --'mi%'
@p3 Int32 --1
@p4 Int32 --2
@p5 Int32 --3

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

ОТВЕТ

Если я изменяю IX_InvertedIndex на кластеризованный индекс, это на порядок увеличивает скорость запроса (хотя я не знаю почему):

CREATE CLUSTERED INDEX IX_InvertedIndex ON InvertedIndex (Term) 

1 Ответ

2 голосов
/ 19 июня 2010

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

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

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

Ваш индекс также должен иметь значение Term с INCLUDE , чтобы EntityType, EntityID тоже покрывал

Редактировать,после комментария.

Вы можете попробовать ПРОДОЛЖИТЬ ПЛАН или План форсирования тоже , учитывая относительную простоту, чтобы избежать того, что звучит как перекомпиляция.

Если этоБыл ли SQL Server 2008, я бы предложил ОПТИМИЗИРОВАТЬ ДЛЯ НЕИЗВЕСТНЫХ

Наконец, еще одна мысль: совпадают ли типы данных по всем направлениям?

Редактировать: Вы должны изменить индекс на(Term, EntityType, Ordinal, EntityID) без ВКЛЮЧЕНО. Вы используете все столбцы в JOIN-файлах или фильтрах

Вам также необходим первичный ключ (Term? Ordinal), который также должен быть уникальным и кластеризованным.нет никакого преимущества в том, чтобы не иметь ничего кроме плохой производительности и фрагментированных данных

И измените запрос на это:

WITH Search AS
(
    SELECT Ordinal, EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p0 AND EntityType = @pPersonEntityType
    INTERSECT
    SELECT Ordinal, EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p1 AND EntityType = @pPersonEntityType
    INTERSECT
    SELECT Ordinal, EntityType, EntityID FROM InvertedIndex WHERE Term LIKE @p2 AND EntityType = @pPersonEntityType
)
SELECT
    p.PersonID, p.FullName, p.Email, p.MobilePhone, p.HomeAddress, p.HomeCity
FROM
    Search AS s
    INNER JOIN
    Person AS p ON p.PersonID = s.EntityID
    LEFT JOIN
    (SELECT 0 AS Ranking, @p3 AS RankOrdinal) O3
    LEFT JOIN
    (SELECT 0 AS Ranking, @p4 AS RankOrdinal) O4
    LEFT JOIN
    (SELECT 0 AS Ranking, @p5 AS RankOrdinal) O5
ORDER BY    --although, I can't see why you are doing + 
    ISNULL(O3.Ranking, 1) +
    ISNULL(O4.Ranking, 1) +
    ISNULL(O5.Ranking, 1)
...