如何使用基本内部联接优化基本MySQL查询?

时间:2012-07-31 01:53:33

标签: mysql optimization indexing

SELECT au.* 
FROM users au 
INNER JOIN friends fa  ON au.id = fa.to_user_id  
WHERE fa.from_user_id = 369 AND fa.persona_id IN('1241') 
GROUP BY au.id 
ORDER BY id DESC 
LIMIT 0, 9999999999;

这是解释

mysql> EXPLAIN SELECT au.* FROM users au INNER JOIN friends fa  ON au.id = fa.to_user_id  WHERE fa.from_user_id = 369 AND fa.persona_id IN('1241') GROUP BY au.id ORDER BY id DESC LIMIT 0, 9999999999;
+----+-------------+-------+-------------+------------------------------------------------------------+------------------------------------+---------+--------------------+------+---------------------------------------------------------------------------------------------------+
| id | select_type | table | type        | possible_keys                                              | key                                | key_len | ref                | rows | Extra                                                                                             |
+----+-------------+-------+-------------+------------------------------------------------------------+------------------------------------+---------+--------------------+------+---------------------------------------------------------------------------------------------------+
|  1 | SIMPLE      | fa    | index_merge | from_user_id,to_user_id,persona_id,from_user_id_persona_id | persona_id,from_user_id_persona_id | 4,8     | NULL               |   49 | Using intersect(persona_id,from_user_id_persona_id); Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | au    | eq_ref      | PRIMARY                                                    | PRIMARY                            | 4       | kjdb.fa.to_user_id |    1 |                                                                                                   |
+----+-------------+-------+-------------+------------------------------------------------------------+------------------------------------+---------+--------------------+------+---------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

我在这张表中只有300,000行,但这是永远的。 (约0.75秒运行它)

mysql> desc friends;
+-------------------+------------+------+-----+---------+----------------+
| Field             | Type       | Null | Key | Default | Extra          |
+-------------------+------------+------+-----+---------+----------------+
| id                | int(11)    | NO   | PRI | NULL    | auto_increment |
| from_user_id      | int(11)    | NO   | MUL | NULL    |                |
| to_user_id        | int(11)    | NO   | MUL | NULL    |                |
| persona_id        | int(11)    | NO   | MUL | NULL    |                |
| action_by_user_id | int(11)    | NO   | MUL | NULL    |                |
| is_disabled       | tinyint(1) | NO   |     | 0       |                |
| created_at        | datetime   | YES  |     | NULL    |                |
| updated_at        | datetime   | YES  |     | NULL    |                |
+-------------------+------------+------+-----+---------+----------------+
8 rows in set (0.01 sec)



> desc users;
+---------------------+--------------+------+-----+---------+----------------+
| Field               | Type         | Null | Key | Default | Extra          |
+---------------------+--------------+------+-----+---------+----------------+
| id                  | int(11)      | NO   | PRI | NULL    | auto_increment |
| username            | varchar(255) | NO   | UNI | NULL    |                |
| first_name          | varchar(255) | NO   | MUL | NULL    |                |
| last_name           | varchar(255) | YES  | MUL | NULL    |                |
| email               | varchar(255) | YES  | UNI | NULL    |                |

这是我的索引:

mysql> show indexes from friends;
+-------------------+------------+-------------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table             | Non_unique | Key_name                | Seq_in_index | Column_name       | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------------------+------------+-------------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+
| friends |          0 | PRIMARY                 |            1 | id                | A         |      388926 |     NULL | NULL   |      | BTREE      |         |
| friends |          0 | from_user_id            |            1 | from_user_id      | A         |          17 |     NULL | NULL   |      | BTREE      |         |
| friends |          0 | from_user_id            |            2 | to_user_id        | A         |      388926 |     NULL | NULL   |      | BTREE      |         |
| friends |          0 | from_user_id            |            3 | persona_id        | A         |      388926 |     NULL | NULL   |      | BTREE      |         |
| friends |          1 | to_user_id              |            1 | to_user_id        | A         |       19446 |     NULL | NULL   |      | BTREE      |         |
| friends |          1 | persona_id              |            1 | persona_id        | A         |       32410 |     NULL | NULL   |      | BTREE      |         |
| friends |          1 | action_by_user_id       |            1 | action_by_user_id | A         |        9972 |     NULL | NULL   |      | BTREE      |         |
| friends |          1 | from_user_id_persona_id |            1 | from_user_id      | A         |        9486 |     NULL | NULL   |      | BTREE      |         |
| friends |          1 | from_user_id_persona_id |            2 | persona_id        | A         |       35356 |     NULL | NULL   |      | BTREE      |         |
+-------------------+------------+-------------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+

2 个答案:

答案 0 :(得分:0)

添加此索引:

ALTER TABLE friends ADD INDEX ix_from_persona_to (from_user_id,persona_id,to_user_id);

看看是否有帮助。

如果没有,您可能需要添加FORCE INDEX

SELECT 
    au.* 
FROM 
    users au 
INNER JOIN 
    friends fa ON au.id = fa.to_user_id  
FORCE INDEX
    (ix_from_persona_to)
WHERE
    fa.from_user_id = 369 AND
    fa.persona_id IN ('1241')
GROUP BY
    au.id 
ORDER BY
    id DESC
LIMIT
    0, 9999999999;

答案 1 :(得分:0)

on group by的顺序导致临时表+ filesort,这会影响你的表现。

尝试subselects?

SELECT au.* 
FROM users au 
WHERE au.id IN (
  SELECT DISTINCT fa.to_user_id 
  FRoM friends fa 
  WHERE fa.from_user_id = 369 AND fa.persona_id IN('1241') 
)
ORDER BY id DESC 
LIMIT 0, 9999999999;

然后在friends.from_user_id,persona_id

上添加索引