Различия между INDEX, PRIMARY, UNIQUE, FULLTEXT в MySQL?
========================================================

Каковы различия между PRIMARY, UNIQUE, INDEX и FULLTEXT при создании таблиц MySQL?

Как я буду использовать их?

 

 Различия
---------

* **KEY** или  **INDEX** относится к нормальному неистинному индексу. Допустимы нечеткие значения для индекса, поэтому индекс может содержать строки с одинаковыми значениями во всех столбцах индекса. Эти индексы не применяют никаких ограничений на ваши данные, поэтому они используются только для обеспечения быстрого выполнения определенных запросов.
* **UNIQUE** относится к индексу, где все строки индекса должны быть уникальными. То есть одна и та же строка может не иметь одинаковых значений, отличных от NULL, для всех столбцов этого индекса в качестве другой строки. Как и для ускорения запросов, индексы UNIQUE могут использоваться для обеспечения ограничений на данные, поскольку система базы данных не допускает нарушения этого правила отдельных значений при вставке или обновлении данных.

Ваша система базы данных может позволить индексу UNIQUE применяться к столбцам, которые допускают значения NULL, и в этом случае двум строкам разрешено быть одинаковыми, если оба они содержат значение NULL (обоснование здесь состоит в том, что NULL считается не равным сам). Однако в зависимости от вашего приложения это может быть нежелательным: если вы хотите предотвратить это, вы должны запретить значения NULL в соответствующих столбцах.
* **PRIMARY** действует точно так же, как индекс UNIQUE, за исключением того, что он всегда называется "PRIMARY", и может быть только один на таблице (и всегда должен быть один, хотя некоторые системы баз данных не применяют это). PRIMARY индекс предназначен в качестве основного средства для однозначной идентификации любой строки в таблице, поэтому в отличие от UNIQUE он не должен использоваться ни в каких столбцах, которые допускают значения NULL. Ваш индекс PRIMARY должен быть на наименьшем числе столбцов, достаточных для однозначной идентификации строки. Часто это всего лишь один столбец, содержащий уникальный автоинкрементный номер, но если есть что-то еще, что может однозначно идентифицировать строку, такую как "код страны" в списке стран, вы можете использовать это вместо этого.

Некоторые системы баз данных (такие как MySQL InnoDB) будут хранить записи таблицы на диске в том порядке, в котором они появляются в индексе PRIMARY.

Индексы
* **FULLTEXT** отличаются от всех вышеперечисленных, и их поведение существенно отличается между системами баз данных. Индексы FULLTEXT полезны только для полнотекстового поиска, выполненного с помощью предложения MATCH()/AGAINST(), в отличие от вышеприведенных трех, которые обычно реализуются внутренне с использованием b-деревьев (что позволяет выбирать, сортировать или диапазоны, начиная с левой колонки) или хеш-таблицы (с учетом выбора, начиная с левой колонки).

Если другие типы индексов являются универсальными, индекс FULLTEXT специализирован, поскольку он служит узкой цели: он используется только для функции "полнотекстового поиска".

 (function(w, d, n, s, t) {
 w[n] = w[n] || [];
 w[n].push(function() {
 Ya.Context.AdvManager.render({
 blockId: "R-A-248011-3",
 renderTo: "yandex\_rtb\_R-A-248011-3",
 async: true
 });
 });
 t = d.getElementsByTagName("script")[0];
 s = d.createElement("script");
 s.src = "//an.yandex.ru/system/context.js";
 s.async = true;
 t.parentNode.insertBefore(s, t);
 })(this, this.document, "yandexContextAsyncCallbacks");

 Сходства
---------

* Все эти индексы могут содержать более одного столбца.
* За исключением FULLTEXT, порядок столбцов является значительным: для того, чтобы индекс был полезен в запросе, запрос должен использовать столбцы из индекса, начинающегося слева - он не может использовать только второй, третьей или четвертой части индекса, если только он не использует предыдущие столбцы в индексе для соответствия статическим значениям. (Чтобы индекс FULLTEXT полезен для запроса, запрос должен использовать все столбцы индекса.)

 

Все это виды индексов.

  **primary:** должен быть уникальным, является индексом, является (вероятным) физическим индексом, может быть только одним в таблице.

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

 (function(w, d, n, s, t) {
 w[n] = w[n] || [];
 w[n].push(function() {
 Ya.Context.AdvManager.render({
 blockId: "R-A-248011-4",
 renderTo: "yandex\_rtb\_R-A-248011-4",
 async: true
 });
 });
 t = d.getElementsByTagName("script")[0];
 s = d.createElement("script");
 s.src = "//an.yandex.ru/system/context.js";
 s.async = true;
 t.parentNode.insertBefore(s, t);
 })(this, this.document, "yandexContextAsyncCallbacks");

  **index:**, если он не является первичным или уникальным, он не ограничивает значения, вставленные в таблицу, но позволяет повысить эффективность поиска.

  **fulltext:** более специализированная форма индексации, позволяющая осуществлять полнотекстовый поиск. Подумайте об этом (по существу), создав "индекс" для каждого "слова" в указанном столбце.

 

Мне кажется, что это было хорошо охвачено, возможно, за исключением следующего:

* Простой `KEY`/`INDEX` (или иначе называемый `SECONDARY INDEX`) увеличивает производительность, если селективность является достаточной. В этом случае обычной рекомендацией является то, что если количество записей в результирующем наборе, на котором применяется индекс, превышает 20% от общей суммы записей родительской таблицы, то индекс будет неэффективным. На практике каждая архитектура будет отличаться, но идея остается верной.
* Вторичные индексы (и это очень специфично для mysql) не должны рассматриваться как полностью отдельные и разные объекты из первичного ключа. Фактически оба они должны использоваться совместно и, как только эта информация известна, предоставляют дополнительный инструмент для DBA mysql: в Mysql индексы вставляют первичный ключ. Это приводит к значительным улучшениям производительности, особенно при умном построении скрытых индексов покрытия, таких как [описанных там](http://www.psce.com/blog/2012/05/17/can-mysql-use-primary-key-values-from-a-secondary-index/)
* Если вам кажется, что ваши данные должны быть `UNIQUE`, используйте уникальный индекс. Вы можете подумать, что это необязательно (например, работать на уровне приложения) и что нормальный индекс будет делать, но на самом деле представляет собой гарантию для Mysql, что каждая строка уникальна, что, кстати, дает преимущество в производительности.
* Вы можете использовать `FULLTEXT` (или иначе называемый `SEARCH INDEX`) с Innodb (в MySQL 5.6.4 и выше) и Myisam Engines
* Вы можете использовать `FULLTEXT` только `CHAR`, `VARCHAR` и `TEXT` типы столбцов
* `FULLTEXT` индекс включает LOT больше, чем просто создание индекса. Там создана группа системных таблиц, полностью отдельная система кеширования и некоторые конкретные правила и оптимизации. См. [http://dev.mysql.com/doc/refman/5.7/en/fulltext-restrictions.html](https://dev.mysql.com/doc/refman/5.7/en/fulltext-restrictions.html) и [http://dev.mysql.com/doc/refman/5.7/en/innodb-fulltext-index.html](https://dev.mysql.com/doc/refman/5.7/en/innodb-fulltext-index.html)