Оптимизировать запрос для объединения таблиц пар ключ / значение в MySQL - PullRequest
0 голосов
/ 15 октября 2018

Есть несколько тем, которые я пробовал, и мои собственные пробные версии и ошибки, но я не могу ускорить выполнение следующего запроса.Запрос работает нормально, но просто ужасно медленно:)

Темы, которые я прочитал и попробовал:

Нужна помощь для оптимизации запроса MySQL с несколькими объединениями

MySQL выбирает из таблицы пар ключ / значение

Внутреннее Объединение двух таблиц на основе всех пар «ключ / значение», точно совпадающих

Объединение результата двух ВНУТРЕННИХ СОЕДИНЕНИЙ одной и той же таблицы в одну временную таблицу в SQL Server

Вот мой запрос:

SELECT `users`.`id`,`users`.`name`,`users`.`email`
FROM `test_users` AS `users`
LEFT JOIN `test_fields_values` AS `fields_values` ON
`fields_values`.`item_id` = `users`.`id`
INNER JOIN `test_fields_values` AS `fields_values_lastname` ON        
`users`.`id` = `fields_values_lastname`.`item_id`
WHERE 
(`fields_values`.`field_id` IS NOT NULL) AND 
(`fields_values_lastname`.`field_id` = 13)
GROUP BY `users`.`id`
ORDER BY `fields_values_lastname`.`value`

Таблицы выглядят какследующим образом.Таблица пользователя:

id | name   | email
--------------------------------
1  | Myself | myself@example.com

Таблица fields_values ​​вместо фактического значения, которое я ввел в имя поля, чтобы его было легче понять, я надеюсь.

field_id | item_id | value
------------------------------------------------------------
4        | 1       | Address
5        | 1       | Phone
6        | 1       | City
7        | 1       | Zipcode
8        | 1       | Email
9        | 1       | Country
10       | 1       | Lastname
11       | 1       | H
12       | 1       | I
13       | 1       | J
14       | 1       | K
15       | 1       | L
16       | 1       | M
17       | 1       | N

The *Поле 1030 * в таблице fields_values соответствует полю id в таблице users.

Моя цель заключается в следующем:

Таблица user содержит около 5500 записей вв нем и в таблице field_values есть 13 записей для каждого пользователя.Сейчас я получаю список пользователей, упорядоченных по фамилии, и показываю их в списке.В этом списке есть фильтр, поэтому список пользователей можно фильтровать по стране / городу и общему поиску.

Фильтры применяются к полю value таблицы fields_values.Так что я могу получить всех пользователей, живущих в Бельгии, например.

Для каждого фильтра я добавляю еще один innerJoin, и поэтому запрос выглядит так:

SELECT `users`.`id`,`users`.`name`,`users`.`email`
FROM `test_users` AS `users`
LEFT JOIN `test_fields_values` AS `fields_values` ON
`fields_values`.`item_id` = `users`.`id`
INNER JOIN `test_fields_values` AS `fields_values_lastname` ON        
`users`.`id` = `fields_values_lastname`.`item_id`
INNER JOIN `test_fields_values` AS `fields_values_country` ON  
`users`.`id` = `fields_values_country`.`item_id`
WHERE 
(
(`fields_values`.`field_id` IS NOT NULL) AND 
(`fields_values_lastname`.`field_id` = 13)) AND 
(`fields_values_country`.`value` = 'belgium')
GROUP BY `users`.`id`
ORDER BY `fields_values_lastname`.`value`

Даже без применения фильтров список занимаеткак 2,5 минуты для загрузки и EXPLAIN показывает мне, что он извлек 73979 записей, что примерно равно 5500 * 13.

Любые подсказки / советы / улучшения приветствуются.Спасибо.

Редактировать:

users стол

CREATE TABLE `test_users` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL DEFAULT '',
`username` VARCHAR(150) NOT NULL DEFAULT '',
`email` VARCHAR(100) NOT NULL DEFAULT '',
`password` VARCHAR(100) NOT NULL DEFAULT '',
`usertype` VARCHAR(25) NOT NULL DEFAULT '',
`block` TINYINT(4) NOT NULL DEFAULT '0',
`sendEmail` TINYINT(4) NULL DEFAULT '0',
`registerDate` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
`lastvisitDate` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
`activation` VARCHAR(100) NOT NULL DEFAULT '',
`params` TEXT NOT NULL,
PRIMARY KEY (`id`),
INDEX `usertype` (`usertype`),
INDEX `idx_name` (`name`),
INDEX `idx_block` (`block`),
INDEX `username` (`username`),
INDEX `email` (`email`)
)
COLLATE='utf8_general_ci';

fields_values стол

CREATE TABLE `test_fields_values` (
`field_id` INT(10) UNSIGNED NOT NULL,
`item_id` VARCHAR(255) NOT NULL COMMENT 'Allow references to items which have strings as ids, eg. none db systems.' COLLATE 'utf8mb4_unicode_ci',
`value` TEXT NOT NULL COLLATE 'utf8mb4_unicode_ci',
INDEX `idx_field_id` (`field_id`),
INDEX `idx_item_id` (`item_id`(191))
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB

Настоящим пояснение:

id  | select_type | table                    | type     | possible_keys              | key            | key_len | ref                                        | rows    | extra
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
"1" | "SIMPLE"    | "fields_values_lastname" | "ref"    | "idx_field_id,idx_item_id" | "idx_field_id" | "4"     | "const"                                    | "3513"  | "Using temporary; Using filesort"
"1" | "SIMPLE"    | "users"                  | "eq_ref" | "PRIMARY"                  | "PRIMARY"      | "4"     | "cms_inter.fields_values_lastname.item_id" | "1"     | "Using where"
"1" | "SIMPLE"    | "fields_values"          | "ALL"    | "id_id,idx_item_id"        | NULL           | NULL    | NULL                                       | "73979" | "Using where; Using join buffer (flat, BNL join)"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...