У меня странная проблема с компиляцией запросов, которую сложно воспроизвести. Это происходит только при высокой нагрузке и не может быть легко повторено.
- Есть таблица T с колонками A, B, C, D.
- Существует неуникальный кластерный индекс на T (A, B, C, D).
- Есть запрос SELECT * ОТ Т, ГДЕ A = @ P1 И B = @ P2 И (C = @ P3 ИЛИ C = @ P4) И D = @ P5. Условие поиска находится во всех столбцах кластеризованного индекса, у 3-го столбца есть ИЛИ.
Проблема в том, что план запроса для этого запроса имеет Предикат поиска только для A и B! Предикат для C и D является обычным предикатом, поэтому это означает, что дерево поиска в столбцах C и D не используется.
Типы данных для всех параметров соответствуют типам данных столбца.
Кто-нибудь может дать какие-нибудь подсказки о том, почему это может происходить? Версия SQL 2008 R2 (SP1) - 10.50.2789.0 (X64)
OPTION (RECOMPILE)
?Ответы:
Для параметризованного запроса он не может просто выполнить два поиска
а также
Потому
@P3 = @P4
что, если это неправильно вернет дубликаты строк. Так что для этого потребуется оператор, который сначала удалит дубликаты из них.Из быстрого теста этот конец, кажется, зависит от размера стола, получите вы это или нет. В приведенном ниже тесте
245
/246
rows - это точка отсечения между планами (это также была точка отсечения между индексом, размещающим все на одной странице, и он стал 2 листами листа и корневой страницей).1 страница / 245 строк
Этот план имеет поиск
A=1 AND B=2
с остаточным предикатом на(C=@C1 OR C=@C2) AND D=5
2 листа страниц / 246 строк
Во втором плане дополнительные операторы несут ответственность за удаление любых дубликатов с
@C1,@C2
первого до выполнения поиска (ов).Поиск во втором плане - это поиск диапазона между остаточным предикатом
A=1 AND B=2 AND C > Expr1010
иA=1 AND B=2 AND C < Expr1011
с остаточным предикатомD=5
. Это все еще не поиск равенства во всех 4 колонках. Более подробную информацию о дополнительных операторах плана можно найти здесь .Добавление
OPTION (RECOMPILE)
действительно позволяет ему проверять значения параметров на наличие дубликатов во время компиляции и создает план с двумя поисками равенства.Вы также можете достичь этого с
Но на самом деле в этом тестовом примере это, скорее всего, будет контрпродуктивно, так как наличие двух поисков в индексе одной страницы вместо одного увеличивает логический ввод-вывод.
источник
select .. union select ...
что также даст вам два поиска плюс дополнительный шаг удаления дубликатов из результата.SELECT * FROM T WHERE A=1 AND B=2 AND C=@C1 AND D=5 UNION SELECT * FROM T WHERE A=1 AND B=2 AND C=@C2 AND D=5
может неправильно удалить дубликаты, которые должны быть возвращены. В моем примере данных, где я лениво заполнял все с одним и тем же значением, он возвращал бы не 1 строку256
Полностью согласен с анализом Мартина. Этот запрос не может произвести поиск по всем 4 столбцам из-за предиката ИЛИ, если (возможно) с OPTION (RECOMPILE). Я предполагаю, что это запрос «иголка в стоге сена», возможно, вам не нужны дополнительные издержки.
Как насчет этого:
Я не проверял это, но остальная часть должна дать 2 поиска по всем 4 значениям и дешевый союз через конкатенацию. В случае, когда оба поиска заканчиваются на одной странице, я не думаю, что дополнительное чтение логической страницы добавит много времени. Однако, в зависимости от ваших данных, два поиска могут быть на разных страницах.
источник