2

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

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

4

1 回答 1

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性能等。

祝你好运。

于 2012-07-12T11:10:42.927 回答