我有两个表,它们之间有一个外键约束
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
最佳答案
根据定义,您的查询确实需要全面扫描。
也就是你不给过滤条件。没有 ... 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
性能等。
祝你好运。
关于mysql - 在外键 : MySQL performance 上连接表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11450116/