Оптимизация запросов на основе кластеризованных и некластеризованных индексов в SQL?

В последнее время я читал о том, как работают clustered index и non-clustered index. Мое понимание простыми словами (поправьте меня, если не так):

Структура данных, которая поддерживает clustered и non-clustered index, равна B-Tree

Clustered Index: физически сортирует данные на основе столбца (или ключа) индекса. у вас может быть только один clustered Index на table. Если во время создания таблицы не указано index, сервер SQL автоматически создаст clustered Index на primary key column.

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

Non-clustered Index: В non-clustered indexes leaf-node дерева содержит значения столбцов и указатель (указатель строки) на фактическую строку в базе данных. Здесь требуется дополнительное пространство для хранения этого non-clustered index table физически на диске. Однако количество non-clustered Indexes. не ограничивается

Q2. Означает ли это, что запрос столбца некластеризованного индекса не приведет к отсортированным данным?

Q3. Здесь связан дополнительный поиск, позволяющий найти фактические данные строки с помощью указателя на листовом узле. Насколько сильно это будет отличаться в производительности по сравнению с кластеризованным индексом?

Упражнение:

рассмотрим таблицу сотрудников:

CREATE TABLE Employee
(
PersonID int PRIMARY KEY,
Name varchar(255),
age int,
salary int
); 

Теперь я создал таблицу сотрудников (создается кластерный индекс по сотруднику по умолчанию).

Два частых запроса к этой таблице выполняются только по столбцам "Возраст" и "Зарплата". Для простоты предположим, что таблица НЕ часто обновляется.

Например:

select * from employee where age > XXX;

select * from employee where salary > XXXX and salary < YYYY;

Q4: как лучше всего построить индексы, чтобы запросы к обоим этим столбцам имели одинаковую производительность. Если у меня есть кластерный индекс по возрасту, запросы по столбцу возраста будут быстрее, но по столбцу зарплаты будут медленнее.

Q5: по теме: я неоднократно видел, что индексы (как кластерные, так и некластеризованные) должны создаваться для столбцов с уникальными ограничениями. это почему? что произойдет, если этого не сделать?

Большое спасибо. Сообщения, которые я прочитал, находятся здесь:

http://javarevisited.blogspot.com/2013/08/difference-between-clustered-index-and-nonclustered-index-sql-server-database.html

http://msdn.microsoft.com/en-us/library/ms190457.aspx

Кластеризованный против некластеризованного

Что на самом деле означают кластерный и некластеризованный индекс?

В чем различия между кластеризованным и некластеризованным индексом?

Как работает индексация базы данных?


person brain storm    schedule 12.09.2014    source источник
comment
Вы отметили этот вопрос как mysql, но ваши вопросы подразумевают, что вы спрашиваете о Microsoft SQL Server. Что он? Оба продукта предоставляют кластерные и некластеризованные индексы, но внутренние детали могут немного отличаться. Не могли бы вы уточнить, а при необходимости отредактировать теги?   -  person Bill Karwin    schedule 12.09.2014
comment
@BillKarwin: Я не спрашиваю о сервере Microsoft SQl. Я хочу, чтобы это был общий вопрос. Общая реализация индексов может отличаться в mysql и Microsoft. но меня интересует концепция / идея того, как это работает. Я не уверен, в какой части вопроса указан сервер Microsoft SQL, если это так, пожалуйста, отредактируйте его. Я здесь новичок, так что, возможно, я неосознанно менял терминологию. Спасибо!   -  person brain storm    schedule 12.09.2014


Ответы (2)


Для SQL Server

Q1 Дополнительное пространство необходимо только для кластерного индекса, если он не является уникальным. SQL Server добавит 4-байтовый уникальный указатель к неуникальному кластеризованному индексу. Это связано с тем, что он использует ключ кластера как идентификатор строки в некластеризованных индексах.

Q2 Некластеризованный индекс можно читать по порядку. Это может помочь запросам, в которых вы указываете заказ. Это также может сделать объединения слиянием привлекательными. Это также поможет с запросами диапазона (x ‹col и y> col).

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

Если требуется поиск по закладке, не требуется большого процента строк, пока не будет проще сканировать весь кластеризованный индекс. Уровень зависит от размера строки, размера ключа и т. Д. Но 5% строк - это типичная обрезка.

Q4. Если в вашем приложении важнее всего было выполнение обоих этих запросов как можно быстрее, вы могли бы создать покрывающий индекс для них обоих:

create index IX_1 on employee (age) include (name, salary);
create index IX_2 on employee (salary) include (name, age);

Обратите внимание, что вам не нужно специально включать ключ кластера, поскольку некластеризованный индекс имеет его как указатель строки.

Q5. Это более важно для кластерных ключей, чем для некластерных ключей из-за уникальности. Однако реальная проблема заключается в том, является ли индекс выборочным или нет для ваших запросов. Представьте себе индекс по значению bit. Если распределение данных не будет очень перекосом, такой индекс вряд ли будет использоваться для чего-либо.


Подробнее об Уникификаторе. Представьте себе и неуникальный кластерный индекс по возрасту, и некластеризованный индекс по заработной плате. Допустим, у вас есть следующие строки:

age | salary | uniqifier
20  | 1000   | 1
20  | 2000   | 2

Тогда индекс заработной платы будет располагать такие строки

1000 -> 20, 1
2000 -> 20, 2

Допустим, вы выполнили запрос select * from employee where salary = 1000, а оптимизатор решил использовать индекс заработной платы. Затем он найдет пару (20, 1) из поиска по индексу, а затем найдет это значение в основных данных.

person Laurence    schedule 12.09.2014
comment
Спасибо, что приложили усилия, чтобы помочь здесь. не могли бы вы уточнить свою точку зрения на Q1. Что касается Q2) запрос выбора для некластеризованного индекса приведет к сортировке только в том случае, если я укажу ORDER BY. (Сверху Так ответьте). В кластерном индексе он сортируется по умолчанию. так что есть дополнительный процесс сортировки в случае некластеризованных индексов правильно? поэтому операция диапазона (age < 30 and age > 60) будет неэффективна в некластеризованных индексах. пожалуйста, объясни - person brain storm; 13.09.2014
comment
+1 хорошо привести примеры того, чем Microsoft отличается от MySQL. Реализации индекса не универсальны. Фактически, стандарт ANSI / ISO SQL вообще не упоминает индексы, поэтому все реализации являются расширениями поставщика для SQL! - person Bill Karwin; 13.09.2014
comment
некластеризованный индекс по-прежнему представляет собой b-дерево, поэтому вы можете читать страницы индекса по порядку. Представьте, что вы хотите узнать, сколько людей находятся в возрасте от 10 до 20. Вы найдете 10 в btree, а затем пройдетесь по порядку, пока не дойдете до 20, считая каждую строку по мере прохождения. - person Laurence; 13.09.2014
comment
Q1) как этот уникальный указатель, который добавляет SQL-сервер, помогает найти эту строку? например, в моем примере выше я создал кластерный индекс по возрасту (который не является уникальным). теперь, когда я выполняю запрос, select * from employee where age=20;, поскольку есть много сотрудников в возрасте 20 лет, как он извлекает все данные - person brain storm; 13.09.2014
comment
В конце я поместил дополнительную информацию об уникификаторе. - person Laurence; 13.09.2014
comment
отличный пример. Спасибо. когда я запрашиваю CLUSTERED INDEX, который соответствует возрасту в приведенном вами примере, select * from employee where age=20. Поиск в b-дереве будет происходить до листового узла. Теперь в листовом узле есть две строки с возрастом = 20. оба будут возвращены? - person brain storm; 13.09.2014

Я не знаю о внутреннем устройстве Microsoft SQL Server, но могу ответить для MySQL, который вы отметили для своего вопроса. Детали могут отличаться для других реализаций.

Q1. Правильно, дополнительное пространство для кластеризованного индекса не требуется.

Что произойдет, если вы отбросите кластерный индекс? Механизм MySQL InnoDB всегда использует первичный ключ (или первый непустой уникальный ключ) в качестве кластеризованного индекса. Если вы определяете таблицу без первичного ключа или отбрасываете первичный ключ существующей таблицы, InnoDB генерирует внутренний искусственный ключ для кластерного индекса. У этого внутреннего ключа нет логического столбца, на который можно было бы ссылаться.

Q2. Порядок строк, возвращаемых запросом, использующим некластеризованный индекс, не гарантируется. На практике это порядок доступа к строкам. Если вам нужно, чтобы строки возвращались в определенном порядке, вы должны использовать ORDER BY в своем запросе. Если оптимизатор может сделать вывод, что ваш желаемый порядок совпадает с порядком, в котором он будет обращаться к строкам (порядок индекса, будь то кластерный или некластеризованный индекс), то он может пропустить этап сортировки.

Q3. Некластеризованный индекс InnoDB не имеет указателя на соответствующую строку в конце индекса, он имеет значение первичного ключа. Таким образом, поиск в некластеризованном индексе на самом деле представляет собой два поиска в B-дереве, первый для поиска листа некластеризованного индекса, а затем второй поиск в кластеризованном индексе.

Это вдвое превышает стоимость поиска по одному B-дереву (более или менее), поэтому InnoDB имеет дополнительную функцию, называемую Адаптивный индекс хеширования. Часто используемые значения кэшируются в AHI, и в следующий раз, когда запрос выполняет поиск кэшированного значения, он может выполнить поиск O (1). В кэше AHI он находит указатель непосредственно на лист кластеризованного индекса, поэтому часть времени исключает оба поиска в B-дереве.

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

Q4. Создайте индексы для обслуживания запросов, которые необходимо оптимизировать. Обычно кластеризованный индекс является первичным или уникальным ключом, и, по крайней мере, в случае InnoDB это необходимо. Ни age, ни salary вряд ли будут уникальными.

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

Q5. InnoDB автоматически создает индекс, когда вы объявляете уникальное ограничение. У вас не может быть ограничения без существующего для него индекса. Если бы у вас не было индекса, как бы движок обеспечил уникальность при вставке значения? Потребуется поискать повторяющееся значение в этом столбце по всей таблице. Индекс помогает сделать уникальные проверки намного более эффективными.

person Bill Karwin    schedule 12.09.2014
comment
Спасибо за прекрасное объяснение. относительно Q3: вы упомянули, что будет выполнено два поиска по b-дереву, но чтобы найти нужную строку, у меня будет три чтения блока (и каждый блок может иметь от 10 строк до 100 в зависимости от размера блока). Итак, теоретически, даже если у меня есть идентификатор первичного ключа, мне нужно прочитать весь блок, пропустить его, пока не найду интересующий идентификатор. Это правильно? - person brain storm; 12.09.2014
comment
Если у вас есть YouTube или любая видеопрезентация вашего выступления, это было бы здорово. Я смотрю слайды, и они просто классные !! - person brain storm; 12.09.2014
comment
Правильный. InnoDB, например, хранит все на страницах одинакового размера (по умолчанию 16 КБ). Некоторое количество строк умещается на одной странице. Но как только страница загружается в память, накладные расходы на ее поиск незначительны. Ввод-вывод для загрузки страницы с диска примерно в 100 000 раз дороже. - person Bill Karwin; 12.09.2014
comment
Похоже, мой доклад был записан ZendCon, когда я представил его там в 2012 году. youtube.com/ смотреть? v = ELR7-RdU9XU - person Bill Karwin; 13.09.2014
comment
Спасибо за видео. скоро посмотрю. Относительно четвертого и пятого кварталов). если в моей таблице уникален только мой первичный ключ, кластеризованный индекс будет работать только на pk (это означает, что у меня не может быть кластеризованного индекса для любого другого столбца. Это применимо и к некластеризованному индексу). Это похоже на серьезное ограничение, учитывая, что запросы фактов, такие как select name from Employee e where e.id =434534, редки (бесполезны) по сравнению с select name from employee e where e.name="Mike" - person brain storm; 13.09.2014
comment
Если вы хотите использовать преимущество кластеризованного индекса в производительности, используйте name в качестве первичного ключа. Или составной ключ, например (name, emp_id). Первичный ключ не обязательно должен быть одним столбцом или целым числом. Или, возможно, вы используете другую СУБД, которая не имеет ограничений MySQL, а вместо этого позволяет определить столбец, не являющийся первичным ключом, в качестве кластерного индекса. - person Bill Karwin; 13.09.2014
comment
Позвольте нам продолжить это обсуждение в чате. - person brain storm; 13.09.2014
comment
Итак, предположим, у меня есть таблица с автоматически увеличивающимся целым числом в качестве первичного ключа, именем (которое не является уникальным) и соответствующим ему значением. Мне нужно выполнить поиск в таблице по строке неуникального имени (2-й столбец). Если я сформирую некластеризованный индекс по этому столбцу, будет ли поиск по этому столбцу быстрее? Если да, то какой ценой? Если нет, то как мне сделать это быстрее? Некоторая информация - добавляемые данные будут иметь имя 2-го столбца, которое не всегда увеличивается, в отличие от первичного ключа. - person SexyBeast; 08.06.2016
comment
@AttitudeMonger, поиск по индексу выполняется быстрее, чем поиск без индекса. Преимущество тем больше, чем больше строк в таблице. Не имеет значения, увеличиваются данные или нет, программное обеспечение СУБД заботится о вставке в индекс в отсортированном порядке. - person Bill Karwin; 08.06.2016
comment
Спасибо, Билл. Другой вопрос - представьте себе такую ​​же таблицу без первичного ключа. Есть два столбца: один - это серийный номер, а другой - URL. Серийные номера могут повторяться, а URL-адреса - нет. Мне нужно будет искать как по серийному номеру (например, получить все URL-адреса для данного серийного номера), так и по URL-адресу (найти, есть ли там URL). Имеет ли смысл создать для этой таблицы два индекса - уникальный индекс URL-адреса и неуникальный индекс серийного номера? - person SexyBeast; 08.06.2016
comment
@AttitudeMonger Для лучшей производительности создайте единый индекс с двумя столбцами. Это выходит далеко за рамки этого ответа. Посмотрите мою презентацию Как создавать индексы, правда youtube.com/watch?v=ELR7- RdU9XU - person Bill Karwin; 08.06.2016