Ответ
Помимо дублирования, расхождение между индексом и таблицей может возникнуть в следующих случаях:
- NULL-значения. Индексы, как правило, не включают строки, где все проиндексированные столбцы содержат NULL. Запрос, ищущий
WHERE column IS NULL, может не использовать индекс. - Несоответствие типов данных. Сравнение без явного приведения типов (например,
VARCHARсINT) может обойти индекс. - Частичное использование составного индекса. Составной индекс (A, B, C) эффективен только для запросов, использующих префикс этого набора (A; A,B; A,B,C). Запрос по полю B или C без A — нет.
- Использование функций или выражений в
WHERE. Индекс строится на исходных значениях колонки. Условия видаWHERE UPPER(name) = 'ALICE'илиWHERE YEAR(date_column) = 2024обычно игнорируют индекс поnameилиdate_column. - Неоптимальный порядок столбцов в составном индексе. Порядок должен соответствовать частотности и селективности запросов.
Пример с функцией:
-- Индекс по `name` НЕ будет использован
SELECT * FROM users WHERE UPPER(name) = 'ALICE';
-- Индекс по `name` БУДЕТ использован
SELECT * FROM users WHERE name = 'Alice';
-- Для первого случая можно создать функциональный индекс: CREATE INDEX idx_upper_name ON users(UPPER(name)); Ответ 18+ 🔞
А, слушай, вот ещё какие подводные ебучки бывают, когда индекс вроде есть, а запрос всё равно ползёт как черепаха по стекловате. Это ж классика, блядь! Помимо того, что данные могут разъебаться, есть ещё куча нюансов, про которые все забывают, а потом охуевают.
Смотри, вот тебе топ причин, почему твой запрос сосёт, а индекс — хуй с ним:
- NULL-значения, ёпта. Индексы — они такие хитрожопые, обычно игнорируют строки, где во всех проиндексированных полях сидит
NULL. Так что если ты ищешьWHERE column IS NULL, то готовься к полному скану таблицы, потому что индекс тебе, скорее всего, не поможет. Он просто не знает про этих невидимок. - Несоответствие типов данных. Ну это вообще пиздец, как часто бывает! База хранит число, а ты в запросе сравниваешь его со строкой, без всякого приведения. Типа
WHERE int_column = '123'. Оптимизатор смотрит на это и думает: «Ну нахуй, тут явное приведение нужно, индекс поint_columnне подходит». И пошёл таблицу драить. - Частичное использование составного индекса. Вот тут, блядь, многие обжигаются. Создали индекс на три поля
(A, B, C). Думают, теперь всё летает. А он, сука, работает только если ты начинаешь с поляA! То есть запросыWHERE A = 1,WHERE A = 1 AND B = 2илиWHERE A = 1 AND B = 2 AND C = 3— да, огонь. А вот если ты полез с запросомWHERE B = 2илиWHERE C = 3— хуй тебе, а не индекс. Он как телефонная книга, отсортированная по фамилии, а потом имени. Попробуй найти всех Васюков по имени «Петя» — нихуя не выйдет, надо листать всю. - Использование функций или выражений в
WHERE. Это, блядь, убийца номер один! Индекс — это слепок исходных данных колонки. А если ты в условии начинаешь эти данные ебашить функциями, то всё, пиши пропало. Индекс становится бесполезным, как зонтик в ураган.
Пример с функцией, чтобы совсем понятно было:
-- Индекс по `name` НЕ будет использован. Потому что в индексе лежит 'Alice', а ты ищешь UPPER('Alice').
-- Оптимизатор не дурак, он не будет для каждой строки вычислять UPPER и потом сравнивать с индексом. Он проще сделает full scan.
SELECT * FROM users WHERE UPPER(name) = 'ALICE';
-- А вот тут индекс по `name` БУДЕТ использован. Всё честно, ищем то, что есть.
SELECT * FROM users WHERE name = 'Alice';
-- Кстати, если уж очень надо искать через UPPER, можно создать специальный, функциональный индекс: CREATE INDEX idx_upper_name ON users(UPPER(name));
- Неоптимальный порядок столбцов в составном индексе. Это уже высший пилотаж, блядь. Порядок полей — это не просто так. Ставить надо сначала самое селективное (то, что лучше всего отсеивает строки) и то, что чаще всего используется в запросах. Если поставить на первое место поле, где у всех строк значение
1, то от такого индекса толку — как от козла молока.
Вот так-то, дружок. База данных — она живая, блядь. Надо с ней аккуратно, с пониманием. А не просто тыкать CREATE INDEX на всё подряд и надеяться на чудо.