需要帮助优化大型表上的sql JOIN查询和索引

问题描述 投票:0回答:2

我在三个表上有一个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)
mysql sql indexing
2个回答
0
投票

((请使用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也可以选择。


0
投票
对于此查询:

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上的过滤比其他过滤器更具选择性。
  • © www.soinside.com 2019 - 2024. All rights reserved.