我有两个表之间有外键约束
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
答案 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
性能等。