我尝试了多个主题,也遇到了自己的尝试和错误,但无法获得以下查询来加快速度。该查询工作正常,但速度非常慢:)
我已阅读并尝试过的主题:
Need Help for Optimizing MySQL query with few joins
MySQL select from key/value pairs table
Inner Joining two tables based on all "Key/Value" Pairs matching exactly
这是我的查询:
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
item_id
表中的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)"