Поиск индекса SQL - PullRequest
       12

Поиск индекса SQL

3 голосов
/ 05 июня 2009

У меня странная вещь, происходящая с запросом. У меня есть таблица с двумя bigints, StartNum и EndNum, которая определяет диапазоны номеров. У меня есть индекс по этим двум столбцам. Запрос принимает заданное число и возвращает диапазон, в который он попадает. Предложение WHERE: where @Num >= StartNum and @Num <= EndNum.

Существует большая разница в профилировщике между поиском числа в начале списка и в конце. Чем дальше вниз по списку число, тем больше операций чтения и длительности. План запроса показывает, что он использует поиск по моему индексу.

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

Мелкий шрифт: Это на SQL 2005 Workgoup Edition. В таблице около 200 000 строк. Индекс некластеризован (кластеризованный индекс находится в столбце идентификаторов, но данные были вставлены в порядке StartNum). Индекс имеет 716 страниц, имеет глубину 3, фрагментирован на 3%.

Ответы [ 3 ]

1 голос
/ 05 июня 2009

Это зависит от вашего запроса. Если вы запрашиваете только эти два значения, например ::100100

SELECT StartNum, EndNum
FROM Books
WHERE (@Num >= StartNum) AND (@Num <= EndNum)

В этом случае SQL Server должен только выполнить поиск по двум индексам для возврата чисел. Два ваших индекса содержат значение, которое вы проиндексировали, и, поскольку это индекс, они отсортированы.

Но я уверен, что вы включили в свой запрос другие столбцы:

SELECT BookID, Title, IDBN, Author, StartNum, EndNum
FROM Books
WHERE (@Num >= StartNum) AND (@Num <= EndNum)

В этом случае SQL Server, как только он обнаружит id строк, соответствующих критериям, должен затем вернуться в базу данных и найти эти строки, чтобы он мог вернуть вам :

  • Название
  • ISBN
  • Автор

в дополнение к уже имеющимся значениям из двух индексов:

  • StartNum
  • EndNum
  • BookID

Примечание: Индекс в StartNum неявно содержит значение кластеризованного ключа, поскольку именно так он знает, какая строка соответствует записи в индексе.

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


Аналогия: Вы просматриваете в указателе книги все ссылки на "шаблоны проектирования".

шаблоны дизайна: 4, 89, 221, 442

Если есть только 4 записи, то все будет в порядке, если вы переместитесь назад на страницу, указанную в индексе. Это называется поиск закладок .

Но что, если в индексе указано 827 ссылок на фразу?

компьютер: 1, 2, 6, [отрывок 825 записей], 1087, 1128

Тогда может быть быстрее прочитать книгу, чтобы найти их самостоятельно. В этом случае мы сдаемся и сканируем всю книгу. SQL Server называет это сканированием кластеризованного индекса , если таблица имеет кластеризованный индекс, или сканирование таблицы , если нет кластеризованного индекса (то есть это «таблица кучи»)


Если вы просто ссылались на StartNum и EndNum в своем запросе (скажем, вы получили счетчик), то я уверен, что вы увидите постоянно низкое число операций чтения и выполнения раз. Но если вы включите другие столбцы, и SQL Server считает, что из этого запроса будет возвращено слишком много строк (например, более 5% таблицы), он просто забудет индекс и просканирует весь таблица.

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

0 голосов
/ 09 июня 2009

взломали!

EndNum всегда> = StartNum, поэтому мне просто нужно найти самый большой StartNum, который равен <= @Num. Я изменил индекс на StartNum desc и запрос на <code>top 1 ... where StartNum <= @Num order by StartNum desc. Теперь для любого значения @Num это просто поиск по индексу с 5 чтениями и длительностью 0, что я и сделал.

Спасибо за помощь, ребята.

0 голосов
/ 06 июня 2009

Вы проиндексированы в StartNum ASC, EndNum DESC?

Поскольку я ожидаю, что он не сможет выполнить два поиска, если вы проиндексированы в StartNum ASC, EndNum ASC. Он должен искать и сканировать.

Другая возможность состоит в том, чтобы индексировать отдельно по StartNum и EndNum (порядок не имеет значения) и посмотреть, будут ли они использовать оба индекса последовательно, а затем выполнить какое-то соединение.

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

У меня проблемы с копированием поведения без реальных столбцов. Я настроил тестовую таблицу с 200000 диапазонами StartNum-EndNum 100-199, 200-299 и т. Д. Я смог получить ее для сканирования кластеризованного индекса, сканирования таблицы и поиска некластеризованного индекса, но ничего близко к тому, что вы говорите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...