Как правильно индексировать таблицу ссылок для соединения многие-ко-многим в MySQL? - PullRequest
29 голосов
/ 21 февраля 2009

Допустим, у меня есть простая таблица «многие ко многим» между таблицами «table1» и «table2», которая состоит из двух полей типа int: «table1-id» и «table2-id». Как мне индексировать эту таблицу ссылок?

Раньше я просто составлял составной первичный индекс (table1-id, table2-id), но я читал, что этот индекс может не работать, если вы измените порядок полей в запросе. Тогда какое же оптимальное решение - создать независимые индексы для каждого поля без первичного индекса?

Спасибо.

Ответы [ 3 ]

29 голосов
/ 21 февраля 2009

Зависит от того, как вы ищете.

Если вы ищете так:

/* Given a value from table1, find all related values from table2 */
SELECT *
FROM table1 t1
JOIN table_table tt ON (tt.table_1 = t1.id)
JOIN table2 t2 ON (t2.id = tt.table_2)
WHERE t1.id = @id

тогда вам нужно:

ALTER TABLE table_table ADD CONSTRAINT pk_table1_table2 (table_1, table_2)

В этом случае table1 будет ведущим в NESTED LOOPS, и ваш индекс будет использоваться только тогда, когда table1 проиндексирован первым.

Если вы ищете так:

/* Given a value from table2, find all related values from table1 */
SELECT *
FROM table2 t2
JOIN table_table tt ON (tt.table_2 = t2.id)
JOIN table1 t1 ON (t1.id = tt.table_1)
WHERE t2.id = @id

тогда вам нужно:

ALTER TABLE table_table ADD CONSTRAINT pk_table1_table2 (table_2, table_1)

по вышеуказанным причинам.

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

/* Check if relationship exists between two given values */
SELECT 1
FROM table_table
WHERE table_1 = @id1
  AND table_2 = @id2

Для такого запроса вам понадобится хотя бы один индекс в обоих столбцах.

Никогда не плохо иметь дополнительный индекс для второго поля:

ALTER TABLE table_table ADD CONSTRAINT pk_table1_table2 PRIMARY KEY (table_1, table_2)
CREATE INDEX ix_table2 ON table_table (table_2)

Первичный ключ будет использоваться для поиска on both values, а для поиска по значению table_1 дополнительный индекс будет использоваться для поиска по значению table_2.

5 голосов
/ 21 февраля 2009

Пока вы указываете оба ключа в запросе, не имеет значения, в каком порядке они находятся в запросе, и не имеет значения, в каком порядке вы указываете их в индексе.

Однако, не исключено, что иногда у вас будет только один или другой из ключей. Если у вас иногда есть только id_1, то это должно быть первым (но вам все еще нужен только один индекс).

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

0 голосов
/ 26 мая 2011

@ Quassnoi, в первом запросе вы на самом деле используете только ключ tt.table_1, как мы видим из предложения WHERE: WHERE t1.id = @id. А во втором запросе - только tt.table_2.

Таким образом, многостолбцовый индекс может быть полезен только в третьем запросе из-за WHERE table_1 = @id1 AND table_2 = @id2. Если такие запросы не будут использоваться, как вы думаете, стоит ли вместо этого использовать два отдельных индекса в один столбец?

...