у меня есть база данных с некоторыми таблицами отношений n: m, и я использую очень большой запрос для объединения всех этих таблиц. Давайте сначала посмотрим на мою базу данных:
Я создал два представления для сравнения производительности.
Первый вид:
CREATE VIEW `band_page1` AS (
SELECT maid, band_name, band_logo, band_img,
(SELECT countries.country_name from countries WHERE band_info.id_country = countries.id) as country,
(SELECT locations.location_name from locations WHERE band_info.id_location = locations.id) as location,
(SELECT status.status_name from status WHERE band_info.id_status = status.id) as status,
(SELECT founding.fyear from founding WHERE band_info.id_founding = founding.id) as founding,
(SELECT active.ayear from active WHERE band_info.id_active = active.id) as active,
(SELECT GROUP_CONCAT(DISTINCT genres.genre_name ORDER BY genres.genre_name)
FROM genres LEFT JOIN band_genres ON band_genres.id_genre = genres.id
WHERE band_genres.id_band = band_info.maid) AS genre,
(SELECT GROUP_CONCAT(DISTINCT themes.theme_name ORDER BY themes.theme_name)
FROM themes LEFT JOIN band_themes ON band_themes.id_theme = themes.id
WHERE band_themes.id_band = band_info.maid) AS themes,
(SELECT GROUP_CONCAT(DISTINCT labels.label_name ORDER BY labels.label_name)
FROM labels LEFT JOIN band_labels ON band_labels.id_label = labels.id
WHERE band_labels.id_band = band_info.maid) AS label
FROM band_info
GROUP BY band_info.maid);
Второй вид:
CREATE VIEW `band_page2` AS (
SELECT band_info.maid, band_info.band_name, band_info.band_logo, band_info.band_img,
(SELECT countries.country_name from countries WHERE band_info.id_country = countries.id) as country,
(SELECT locations.location_name from locations WHERE band_info.id_location = locations.id) as location,
(SELECT status.status_name from status WHERE band_info.id_status = status.id) as status,
(SELECT founding.fyear from founding WHERE band_info.id_founding = founding.id) as founding,
(SELECT active.ayear from active WHERE band_info.id_active = active.id) as active,
GROUP_CONCAT(DISTINCT genres.genre_name ORDER BY genres.genre_name) AS genre,
GROUP_CONCAT(DISTINCT themes.theme_name ORDER BY themes.theme_name) AS themes,
GROUP_CONCAT(DISTINCT labels.label_name ORDER BY labels.label_name) AS label
FROM band_info
LEFT JOIN band_genres ON band_genres.id_band = band_info.maid
LEFT JOIN band_themes ON band_themes.id_band = band_info.maid
LEFT JOIN band_labels ON band_labels.id_band = band_info.maid
LEFT JOIN genres ON genres.id = band_genres.id_genre
LEFT JOIN themes ON themes.id = band_themes.id_theme
LEFT JOIN labels ON labels.id = band_labels.id_label
GROUP BY band_info.maid);
Когда я захожу в phpmyadmin и открываю представление, на обоих представлениях уходит 3 секунды, чтобы показать результат запроса. Я использую это представление, чтобы сделать запрос, подобный следующему:
SELECT * FROM band_page1 where maid = '$id';
С php кажется, что требуются годы, пока я не получу результат обратно.
Это не только займет 3 секунды, это займет даже гораздо больше времени.
У меня вопрос, как я могу оптимизировать свои запросы?
Существует такая вещь, как «чрезмерная нормализация».
Существуют стандартные «коды стран», которые состоят из 2 букв. Сделать их CHAR(2) CHARACTER SET ascii
, вместо INT
к другому столу. Это сокращает этот столбец с 4 байтов до 2. И избавляется от поиска.
YEAR
является 2-байтовым типом данных; не надо нормализовать такое.
Рассмотреть возможность поворота status
в 1 байт ENUM
вместо поиска.
И могут быть другие.
VIEWs
являются синтаксическим сахаром, и никогда не улучшают производительность. Иногда производительность значительно хуже.
Я не думаю, что есть какая-то польза для GROUP BY
в первый VIEW
,
band_*
Таблицы кажутся таблицами сопоставления «многие ко многим». Их производительность может быть улучшена следующим эти советы.
Других решений пока нет …