mysql - 在外键 : MySQL performance 上连接表

标签 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

最佳答案

根据定义,您的查询确实需要全面扫描。

也就是你不给过滤条件。没有 ... 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/

相关文章:

mysql - 使用多个值更新和 CONCAT

php - Jquery AJAX 未在 PHP 上传递 “POST” 数据

mysql - 如何在 MySQL 中提取部分 Base64 编码的字符串?

hadoop - 重新编写联接查询

mysql - 如何优化跨三个表、40k 行且仅返回 22 个结果的慢速 "select distinct"查询

mysql - 如何正确排除相互引用的行?

mysql - 用于显示大量 INSERT - UPDATE 查询的进度栏

mysql CASE WHEN 要么但不是两者

mySQL:这是递归(或相互依赖)的一种形式吗?

mysql - 如何优化简单 Web 和数据库应用程序的响应时间