Жорстке і швидке правило для включення стовпців в індекс


38

Чи є якесь жорстке і швидке правило визначити, які стовпці та в якому порядку вони слід розміщувати Включено в некластеризований індекс. Я щойно читав цей пост https://stackoverflow.com/questions/1307990/why-use-the-include-clause-when-creating-an-index, і я виявив, що для наступного запиту:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5

Плакат запропонував зробити індекс таким:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(EmployeeID, DepartmentID)
  INCLUDE (Lastname)

ось моє запитання, чому ми не можемо зробити індекс таким

CREATE NONCLUSTERED INDEX NC_EmpDep 
      ON Employee( EmployeeID, DepartmentID, LastName)

або

    CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)

і те, що спонукає плаката вирішити, щоб увімкнути стовпчик LastName. Чому б не інші стовпці? і як вирішити, в якому порядку ми повинні зберігати колонки там?


3
Включити зазвичай повинні поля, які вам потрібні ПІСЛЯ того, як буде знайдено запис, заощаджуючи назад, щоб отримати більше даних. Порядок полів у складі INCLUDE не важливий.
Джимбо

Ryk, особисто я вважаю цей пост корисним.
Джейсон Янг

Я також вважаю це питання корисним. Давайте зосередимось на хороших запитаннях та хороших відповідях, а не на заїжджих людях ....
Volvox

Відповіді:


47

Пропозиція від індексу marc_s неправильна. Я додав коментар. (І моя відповідь була прийнята теж!)

Індекс для цього запиту буде

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (Lastname, EmployeeID)

Зазвичай індекс є

CREATE INDEX <name> ON <table> (KeyColList) INCLUDE (NonKeyColList)

Де:

  • KeyColList = Ключові стовпці = використовується для обмеження рядків та обробки
    БУДИ, ПРИЄДНАЙТЕСЬ, ЗАКАЗУЙТЕ, ГРУПУ ПО тощо
  • NonKeyColList = Неклавішні стовпці = використовується у SELECT та агрегації (наприклад, SUM (col)) після вибору / обмеження

+1 - Я погоджуюсь (див. Мої відповіді), що вибіркові індекси в ОП не варті запиту!
JNK

Чудово! ще одне, що визначатиме порядок KeyColList та NonKeyColList. Чи можете ви просто пояснити моїм прикладом? Припустимо, тепер мій запит: SELECT EmployeeeID, DepartmentID, LastName FROM EmployeeWHERE DepartmentID = 5, StateID = 4 Яким може бути індекс зараз?

@Rocky - NonKeyColListзамовлення не має значення. KeyColListпорядок повинен бути в порядку частоти, ви очікуєте їх використання в запитах. Дивіться мої замітки до моєї відповіді нижче, але це як Last Name, First Name, Middile Initialу телефонній книзі. Перше поле вам потрібно для того, щоб знайти друге поле.
JNK

@gbn Чи дійсно ми вимагаємо EmployeeID в список включень? Як якщо у нас є кластерний індекс у стовпчику EmployeeID і поверх цього, якщо ми створюємо некластеризований індекс у колонці DeptId, таким чином, індекс NonClustered вже має посилання на ключ кластеризації, який включений у структуру індексу NonClustered Index, включаючи ключ кластеризації у списку INCLUDE не ' t додавати будь-які переваги.
Viswanathan Iyer

1
@ViswanathanIyer він не буде доданий двічі, хоча до фактичного дискового сховища: SQL Server виявляє це. Тому вона не потрібна, але це робить речі зрозумілішими. Однак ми не знаємо жодних кластеризованих індексів у питанні, тому безпечніше вважати жодним.
gbn

19

JNK та gbn дали чудові відповіді, але також варто розглянути велику картину - не просто зосередитись на одному запиті. Хоча цей конкретний запит може отримати користь від індексу (№1):

Employee(DepartmentID) INCLUDE (Lastname, EmployeeID)

Цей індекс зовсім не допомагає, якщо запит трохи зміниться, наприклад:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5 AND LastName = 'Smith'

Для цього знадобиться індекс (№2):

Employee(DepartmentID, LastName) INCLUDE (EmployeeID)

Уявіть, що у вас було 1000 співробітників у відділі 5. Використовуючи індекс №1, щоб знайти усіх Смітів, вам потрібно буде пройти всі 1000 рядків у відділі 5, оскільки включені стовпці не є частиною ключа. Використовуючи індекс №2, можна звернутися безпосередньо до відділу 5, LastName Smith.

Таким чином, індекс №2 є більш корисним при обслуговуванні більш широкого спектру запитів - але вартість є більш роздутим індексним ключем, що зробить сторінки, що не містять листів, індексу. Кожна система буде різною, тому тут немає принципового правила.


В якості бічної примітки варто зазначити, що якщо EmployeeEID був ключем кластеризації для цієї таблиці - якщо припустити кластерний індекс - то вам не потрібно включати EmployeeID - він присутній у всіх некластеризованих індексах, тобто індекс №2 міг би просто бути

Employee(DepartmentID, LastName)

2
+1 для отримання більш корисної інформації. Для вашого останнього моменту я перевірив це, і явне використання EmployeeeID в INCLUDE насправді ігнорується (виходячи з розміру індексу), якщо EmployeeID - це кластерний індекс. Це більш очевидно, хоча я думаю, і немає місця простору.
gbn

1
Я абсолютно згоден - завжди краще бути явним, особливо якщо це нічого не коштує!

1
На всякий випадок ... я маю на увазі, що я перевірив кластерний ключ у складі INCLUDE (не явно є EmployeeID), і він не додає місця. У ключових стовпцях це робиться.
gbn

@gbn Так, кластер кластеру повинен міститись лише на рівні аркушів індексу, де містяться стовпці INCLUDE. Переміщення його в індексний ключ означало б, що воно буде існувати і на нелістових сторінках. Це призведе до трохи роздуття, але не страшної кількості (на сторінках проміжного рівня ви додасте ще 4 байти на сторінку рівня аркуша, припускаючи цілий ряд).

Це чудова відповідь, яка включає деякі ефекти, описані в цій статті: sqlperformance.com/2014/07/sql-indexes/… Якщо ваш запит змінюється, то це стосується і вимог ваших індексів. Можливо, вам буде краще з відповіддю Джима, але ви можете скористатися відповіддю @gbn.
Джон ака hot2use

7

Я не впевнений, як у вас з’явився той перший. Для мене для цього запиту я використовував би:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (EmployeeID, Lastname)

Існує не "жорстке і швидке правило" для майже нічого в SQL.

Але, для вашого прикладу, єдине поле, яке використовуватиме індекс, це DepartmentIDтому, що воно знаходиться в WHEREпункті.

Інші поля просто повинні бути легко доступними звідти. Ви вибираєте, виходячи з DepartmentIDтогоINCLUDE має ці поля в аркуші аркуша індексу.

Ви не хочете використовувати інші ваші приклади, оскільки вони не працюватимуть для цього індексу.

Подумайте про індекс, як телефонну книгу. Більшість телефонних книг упорядковані Прізвищем, Іменем, Середнім Ініціалом. Якщо ви знаєте чиєсь прізвище, але не його прізвище, телефонна книга не приносить вам користі, оскільки ви не можете шукати ім'я на основі порядку індексу телефонної книги.

The INCLUDE поля, як номер телефону, адреса і т.д. інша інформація для кожного запису в книзі.

Редагувати:

Щоб додатково уточнити, чому не використовувати:

CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)

Цей показник є тільки корисним , якщо у вас є або EmployeeIDчи ОБИДВА EmployeeID і LastNameв вашому WHEREреченні. Це в значній мірі ОПОЗИЦІЯ того, що вам потрібно для цього запиту.


@ajbeaven це правда, саме тому коментар, який я помістив у редагування, говорить про те, що вам потрібен EITHER служительID або обидва стовпці.
JNK

durr вибачте неправильно :(
ajbeaven

0

Я думаю, що ви все ще зможете використовувати індекс (служитель_id, відділ_id), але вам доведеться включати рядок "манекен" у фразу де, наприклад: "службовець_id = працівник_id"

  • маючи індекс на (Employ_id, departemnent_id),
  • шукати / обмежувати лише у відділі_id
  • знаючи, що він не буде використовувати індекс, оскільки неправильний порядок (або все змінилося на сьогоднішній день, і наступний "трюк" більше не потрібен. Я "старий"?) .
  • Використовуєте "старий" трікК?

    виберіть * із співробітника emp,
    де emp.employee_id = emp.employee_id
    та emp.department_id = 5

(Тому я не зосереджуюсь на включенні тут частини прізвища, а на так / або не використовуваний ключ.)

З повагою,

Мігель


2
Ні, це марно і не ефективно.
ypercubeᵀᴹ

Зокрема, потрібно буде провести сканування індексу для пошуку кожного ідентифікатора співробітника, щоб знайти всі екземпляри Department_id 5. Якщо є 1000 співробітників і 5 відділів, SQL повинен переглядати всіх 1000 співробітників, щоб знайти всі рядки для певного відділу.
Марк Совул

Тепер розглянемо протилежний випадок (індекс знаходиться на Department_id, служитель_id). Очевидно, що зараз знайти певний відділ легко, але також зауважте, що для пошуку конкретного співробітника SQL має лише просканувати 5 відділів, щоб знайти всі рядки для конкретного працівника.
Марк Совул
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.