Предупреждение SQL Server 2000 “НЕТ ПРЕДИКАТА СОЕДИНЕНИЯ” - почему?
-
08-07-2019 - |
Вопрос
У меня странная проблема с SQL Server 2000, и я просто не могу придумать причину, по которой это могло произойти.
Есть две таблицы, обе имеющие объединенный первичный ключ с кластеризованным индексом на нем, оба ключа имеют одинаковую структуру:
(VARCHAR(11), INT, DATETIME) /* can't change this, so don't suggest I should */
Итак, присоединиться к ним таким образом достаточно просто:
SELECT t1.Foo, t2.Bar
FROM table1 t1 INNER JOIN table2 t2 ON t1.VarcharKey = t2.VarcharKey
WHERE t1.VarcharKey = 'Foo'
Глядя на план выполнения запроса, я вижу это:
- Кластеризованный поиск по индексу [db].[dbo].[table1].[PK_table1] (48%)
- Кластеризованный поиск по индексу [db].[dbo].[table2].[PK_table2] (51%)
- Вложенные циклы (внутреннее соединение) (1%) Предупреждение:НЕТ ПРЕДИКАТА ОБЪЕДИНЕНИЯ
- Выберите (0%)
Теперь, если я сделаю это (обратите внимание на строку NVARCHAR!):
SELECT t1.Foo, t2.Bar
FROM table1 t1 INNER JOIN table2 t2 ON t1.VarcharKey = t2.VarcharKey
WHERE t1.VarcharKey = N'Foo'
Я получаю:
- Сканирование кластеризованного индекса [db].[dbo].[table1].[PK_table1] (98%)
- Кластеризованный поиск по индексу [db].[dbo].[table2].[PK_table2] (1%)
- Вложенные циклы (внутреннее соединение) (1%) здесь нет предупреждения
- Выберите (0%)
Такое поведение оставляет меня немного озадаченным.
- Почему появляется предупреждение "NO JOIN PREDICATE" и почему оно исчезает, когда я меняю
'Foo'
ДляN'Foo'
?Мои ключевые столбцы не имеют типа NVARCHAR, так что это не должно иметь никакого значения, или должно? - Имеет ли наличие этого предупреждения негативные последствия или я могу его проигнорировать?
- Почему он переключается с поиска по индексу на сканирование по индексу?
Некоторая справочная информация:Мощность таблицы составляет ок.25 000 записей в одной таблице, ок.12 000 записей в другом.Уровень совместимости базы данных равен 80 (SQL Server 2000) параметры сортировки по умолчанию равны SQL_Latin1_General_CP1_CI_AS
, если это вообще имеет какое-то значение.
Вот содержание @@VERSION
:
Microsoft SQL Server 2000 - 8.00.2273 (Intel X86) 7 марта 2008 22:19:58 Авторское право (c) 1988-2003 Microsoft Corporation Enterprise Edition на Windows NT 5.0 (сборка 2195:Пакет обновления 4)
P.S.:Я осознаю КB322854, но это, очевидно, не то.
Решение
Почему он переключается с поиска по индексу на сканирование по индексу?
Это в значительной степени предположение, но вот что:
В первом случае ('Foo') MSSQL распознает, что искомое значение идеально соответствует первой части индекса в t1, и поэтому использует индекс для поиска записи в t1 (поиск по индексу, возможно, двоичный поиск).Найдя запись в t1, индекс которой идеально соответствует t2, он может использовать индекс для поиска записей в t2.
Во втором случае (N'Foo') MSSQL распознает, что у него НЕТ идеального соответствия между индексом и запрашиваемым значением, поэтому он не может использовать индекс в качестве индекса, но должен выполнить полное сканирование таблицы.Однако, поскольку индекс содержит необходимую информацию (в другой форме) и меньше, чем полная таблица, он может выполнить полное сканирование индекса, как если бы это была таблица (это быстрее, чем сканирование таблицы, поскольку для чтения с диска требуется меньше страниц;тем не менее, похоже, что это занимает примерно в 90 раз больше времени, чем поиск по индексу)
Другие советы
запросы могут иметь то, что выглядит как идеально сформированное условие соединения.Но когда вы изучите план запроса, вы увидите предупреждение "Нет предиката объединения", указывающее на то, что 2 из задействованных таблиц не имеют предиката (при объединении).Добавление опции (принудительный порядок) к запросу приводит к созданию совершенно другого плана, и предупреждение исчезает (в некоторых случаях).Вот откуда вы знаете, что это и есть проблема.Большинство запросов, которые я видел, которые работают лучше на SQL 2000, демонстрируют эту проблему.Предполагается, что накопительное обновление 4 до SP 2 должно решить проблему.