连接外键表:MySQL性能

时间:2012-07-12 10:42:07

标签: mysql query-optimization

我有两个表之间有外键约束

Table event
mysql> describe event;
+------------+------------------+------+-----+---------+-------+
| Field      | Type             | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+-------+
| sid        | int(10) unsigned | NO   | PRI | NULL    |       |
| cid        | int(10) unsigned | NO   | PRI | NULL    |       |
| signature  | int(10) unsigned | NO   | MUL | NULL    |       |
| timestamp  | datetime         | NO   | MUL | NULL    |       |
| is_deleted | tinyint(1)       | NO   | MUL | 0       |       |
+------------+------------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

Table signature
mysql> describe signature;
+--------------+------------------+------+-----+---------+----------------+
| Field        | Type             | Null | Key | Default | Extra          |
+--------------+------------------+------+-----+---------+----------------+
| sig_id       | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| sig_name     | varchar(255)     | NO   | MUL | NULL    |                |
| sig_class_id | int(10) unsigned | NO   | MUL | NULL    |                |
| sig_priority | int(10) unsigned | YES  |     | NULL    |                |
| sig_rev      | int(10) unsigned | YES  |     | NULL    |                |
| sig_sid      | int(10) unsigned | YES  |     | NULL    |                |
| sig_gid      | int(10) unsigned | YES  |     | NULL    |                |
+--------------+------------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)

event.signature是一个外键并链接到signature.sig_id。两者都有索引

表事件很大(比如1M记录),而表签名相对较小(最多几千)

访问任何签名属性的已加入查询需要很长时间才能执行。看一下解释

mysql> explain select event.sid,event.cid,signature.sig_name from event join signature on signature.sig_id=event.signature;
+----+-------------+-----------+------+--------------------------------+-----------------------+---------+-------------------------+------+--------------------------+
| id | select_type | table     | type | possible_keys                  | key                   | key_len | ref                     | rows | Extra                    |
+----+-------------+-----------+------+--------------------------------+-----------------------+---------+-------------------------+------+--------------------------+
|  1 | SIMPLE      | signature | ALL  | PRIMARY,index_signature_sig_id | NULL                  | NULL    | NULL                    |  127 |                          |
|  1 | SIMPLE      | event     | ref  | index_event_signature          | index_event_signature | 5       | snorby.signature.sig_id |   68 | Using where; Using index |
+----+-------------+-----------+------+--------------------------------+-----------------------+---------+-------------------------+------+--------------------------+
2 rows in set (0.00 sec)

如果没有访问签名属性

mysql> explain select event.sid,event.cid from event join signature on signature.sig_id=event.signature;
+----+-------------+-----------+-------+--------------------------------+------------------------+---------+-------------------------+------+--------------------------+
| id | select_type | table     | type  | possible_keys                  | key                    | key_len | ref                     | rows | Extra                    |
+----+-------------+-----------+-------+--------------------------------+------------------------+---------+-------------------------+------+--------------------------+
|  1 | SIMPLE      | signature | index | PRIMARY,index_signature_sig_id | index_signature_sig_id | 4       | NULL                    |  127 | Using index              |
|  1 | SIMPLE      | event     | ref   | index_event_signature          | index_event_signature  | 5       | snorby.signature.sig_id |   68 | Using where; Using index |
+----+-------------+-----------+-------+--------------------------------+------------------------+---------+-------------------------+------+--------------------------+
2 rows in set (0.00 sec)

可以看出,如果查询了Signature属性,它会使用ALL连接类型执行完整扫描。

是否可以更快地重写查询?我问这个是因为这是多表连接和加入事件的一部分,签名是阻碍查询速度极慢的瓶颈

我使用5.1.52 MySQL和SQLAlchemy 0.7.8作为ORM

1 个答案:

答案 0 :(得分:1)

根据定义,您的查询 需要完整扫描。

也就是说,你没有给出过滤条件。例如,没有... WHERE sig_rev = 17

因此,这里没有太大的改进。 MySQL选择一个表开始,进行完整扫描,每行从第二个表中获取匹配的行。

所以扫描是必不可少的。但您可以将其转换为索引扫描而不是表扫描。我假设您只在signature列上有一个索引,而且只在sig_id列上。

您可能会在sig_id, sig_name上创建一个额外的索引,如下所示:

ALTER TABLE signature ADD UNIQUE INDEX(sig_id, sig_name);

根据定义,索引是唯一的,因为它比PRIMARY KEY更宽,但这不在重点之列。

您现在可能获得的是一个类似于您发布的第二个示例的执行计划:signature上的索引扫描,然后是事件的索引查找。

确保比较并验证您是否确实在此特定查询上获得了性能提升。检查新索引是否不会影响INSERT性能等。

祝你好运。