我在三个表上有一个JOIN查询,这需要很长时间才能运行。我在其中一个表上为外键(user_shared_url_id)和WHERE子句中的两列(event_result,已启用)创建了索引,因此它的索引总数为三列。与仅使用外键的索引(user_shared_url_id)似乎没有什么不同。其他两个表正在使用单列索引。我的用户表大约有20,000行,但是其他两个表很大,大约有2000万行。我无法完成不到一分钟左右的查询。谁能想到我可以做些潜在的优化来加快速度?我可以使用其他索引或对自定义索引进行改进吗?
表格:
mysql> describe user_shared_urls;
+--------------------+-----------------------------------------------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+-----------------------------------------------------------+------+-----+---------------------+----------------+
| user_id | int(11) unsigned | NO | MUL | NULL | |
| created | timestamp | NO | | CURRENT_TIMESTAMP | |
| last_shared | timestamp | NO | | 0000-00-00 00:00:00 | |
| viewed | tinyint(1) | YES | | 0 | |
| user_shared_url_id | int(11) | NO | PRI | NULL | auto_increment |
| target_url | text | YES | | NULL | |
+--------------------+-----------------------------------------------------------+------+-----+---------------------+----------------+
mysql> desc users
-> ;
+---------------------+-------------------------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+-------------------------------------+------+-----+-------------------+----------------+
| user_id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| last_login | int(11) unsigned | YES | | 0 | |
| roles | varchar(500) | YES | | NULL | |
| first_name | varchar(200) | YES | | NULL | |
| last_name | varchar(100) | YES | | NULL | |
| org_id | int(11) unsigned | NO | MUL | NULL | |
| user_email | varchar(100) | NO | | NULL | |
| created | timestamp | NO | | CURRENT_TIMESTAMP | |
+---------------------+-------------------------------------+------+-----+-------------------+----------------+
mysql> describe user_share_events;
+-----------------------+------------------------------------------------------------------------------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+------------------------------------------------------------------------------------------+------+-----+-------------------+----------------+
| user_share_event_id | int(11) | NO | PRI | NULL | auto_increment |
| event_result | tinyint(1) unsigned | YES | MUL | NULL | |
| user_shared_url_id | int(11) | NO | MUL | NULL | |
| enabled | tinyint(1) | NO | | 1 | |
+-----------------------+------------------------------------------------------------------------------------------+------+-----+-------------------+----------------+
我的索引:
CREATE INDEX usuid_result_enabled ON user_share_events(user_shared_url_id,event_result,enabled);
我的查询:
SELECT
users.user_id,
users.user_email "user_email",
users.roles "role",
CONCAT(users.first_name, ' ', users.last_name) "name",
usus.target_url
FROM
user_shared_urls usus
JOIN users ON usus.user_id = users.user_id
JOIN user_share_events uses FORCE INDEX FOR JOIN (usuid_result_enabled) ON usus.user_shared_url_id = uses.user_shared_url_id
WHERE
users.org_id = 1010
AND
uses.event_result IS NOT NULL
AND
uses.enabled = '1';
解释以上查询的输出:
+----+-------------+-------+------+----------------------+----------------------+---------+--------------------------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+----------------------+----------------------+---------+--------------------------------+------+--------------------------+
| 1 | SIMPLE | users | ref | PRIMARY,org_id | org_id | 4 | const | 403 | NULL |
| 1 | SIMPLE | usus | ref | PRIMARY,user_id | user_id | 4 | luster.users.user_id | 231 | NULL |
| 1 | SIMPLE | uses | ref | usuid_result_enabled | usuid_result_enabled | 4 | luster.usus.user_shared_url_id | 1 | Using where; Using index |
+----+-------------+-------+------+----------------------+----------------------+---------+--------------------------------+------+--------------------------+
3 rows in set (0.00 sec)
((请使用SHOW CREATE TABLE
;比DESCRIBE
更具描述性。)
更改您添加到的索引
INDEX(user_shared_url_id, -- = and used for the JOIN
enabled, -- =
event_result) -- Last (not an = test)
INDEX
中的列顺序很重要。从测试=
(或IS NULL
)的列开始。
然后删除FORCE INDEX
,然后再次运行EXPLAIN
。
这些表是否具有1:many
关系?告诉我们哪种方式。
另一条评论:如果event_result
实际上只有两个值(是/否),并且您将NULL
用作假,则将query更改为
uses.event_result IS NOT NULL
to
uses.event_result = 1
关键是优化器喜欢优化=
,但认为NOT NULL
是256个可能的值中的任何一个;距=
很远。通过此[[query更改,您的索引应该可以工作。甚至不用FORCE
也可以选择。
SELECT u.user_id, u.user_email, u.roles "role",
CONCAT(u.first_name, ' ', u.last_name) "name",
usu.target_url
FROM user_shared_urls usu JOIN
users u
ON usu.user_id = u.user_id JOIN
user_share_events usev
ON usus.user_shared_url_id = usev.user_shared_url_id
WHERE u.org_id = 1010 AND
usev.event_result IS NOT NULL AND
usev.enabled = 1;
最好的索引可能是:
users(org_id, user_id)
user_shared_urls(user_id, user_shared_url_id)
user_share_events(user_shared_url_id, enabled, event_result)
org_id
上的过滤比其他过滤器更具选择性。