Чрезвычайно медленный SQL-запрос при использовании нескольких внутренних предложений join и order - PullRequest
1 голос
/ 10 июля 2019

У меня есть база данных MySQL с тремя соответствующими таблицами, t1 с 6598 строками, t2 с 1713 строками и t3 с 10023 строками.

Подробности:

TABLE t1 (
    `id` SERIAL,
    `t2_id` BIGINT UNSIGNED NOT NULL,
    `t3_id` BIGINT UNSIGNED,
    PRIMARY KEY (`id`),
    FOREIGN KEY (t2_id) REFERENCES t2(id),
    FOREIGN KEY (t3_id) REFERENCES t3(id)   
);

TABLE t2(
    `id` SERIAL,
    `name` VARCHAR(128) NOT NULL,
    PRIMARY KEY (`id`)
);

TABLE t3 (
    `id` SERIAL,
    `name` VARCHAR(128),
    PRIMARY KEY (`id`)
);

Я хочу выполнить следующий запрос, но он не завершается (в основном занимает вечность):

SELECT *
FROM t1
INNER JOIN t3
ON t1.t3_id = t3.id
INNER JOIN t2
ON t1.t2_id = t2.id
WHERE (t3.name NOT NULL)
ORDER BY t3.name ASC , t1.id ASC
LIMIT 25

Когда я удаляю предложение, оно работает очень быстро (0,17 с).

Как я могу изменить запрос, чтобы он работал?

Ответы [ 2 ]

1 голос
/ 10 июля 2019

Я могу предложить следующие индексы:

CREATE INDEX idx_t1 ON t1 (t2_id, t3_id, id);
CREATE INDEX idx_t3 ON t3 (id, name);

Эти индексы, по крайней мере, должны существенно ускорить соединения.В случае использования MySQL, скорее всего, будет использовать следующую стратегию объединения:

SELECT *
FROM t2
INNER JOIN t1
    ON t2.id = t1.t2_id
INNER JOIN t3
    ON t1.t3_id = t3.id
WHERE
    t3.name IS NOT NULL
ORDER BY
    t3.name,
    t1.id
LIMIT 25;

Идея здесь заключается в том, что мы выполняем полное сканирование таблицы на t2, который является самой маленькой таблицей.В любом случае, нет никаких ограничений на записи в t2, поэтому мы могли бы сначала отсканировать это.Затем для каждого из соединений с t1 и t3 мы пытаемся использовать настройку индексов.Обратите внимание: поскольку в ваших таблицах относительно мало столбцов, два указанных индекса могут легко охватывать все столбцы, что увеличивает вероятность того, что MySQL выберет использование индексов.

0 голосов
/ 12 июля 2019

t1 - таблица сопоставления «многие: многие».Для ПК не нужен суррогат id.Вместо этого ему нужен составной PK двух других столбцов, плюс индекс в другом направлении.

См. http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table для обсуждения этих и нескольких других советов.

...