Mysql IN()与UNION ALL性能

Mysql IN()与UNION ALL性能,mysql,sql,database,Mysql,Sql,Database,有人能解释一下以下两个查询(如果有的话)在性能特征上的差异吗 问题1 问题2 我知道查询1对人类来说要清晰得多 我感兴趣的是讨论它们的性能特征如何相同或不同。您可以假设有一个关于用户的索引。status在第二次查询中,您单独查询表。对于每个选择,它必须读取一个表。在第一种方法中,它必须读取表一次 有了索引,性能不会有太大的不同 如果没有索引,每个表读取都必须是全表扫描,这两种方法之间的性能差异将更大 因此,第一个查询会更快。有了索引,从性能角度来看,这两个查询应该基本上是等价的。索引可用时的基本

有人能解释一下以下两个查询(如果有的话)在性能特征上的差异吗

问题1 问题2 我知道查询1对人类来说要清晰得多


我感兴趣的是讨论它们的性能特征如何相同或不同。您可以假设有一个关于用户的索引。status

在第二次查询中,您单独查询表。对于每个选择,它必须读取一个表。在第一种方法中,它必须读取表一次

有了索引,性能不会有太大的不同

如果没有索引,每个表读取都必须是全表扫描,这两种方法之间的性能差异将更大


因此,第一个查询会更快。

有了索引,从性能角度来看,这两个查询应该基本上是等价的。索引可用时的基本过程是索引查找,以获取匹配的行,然后获取数据页。第一种方法在单个查询单元中执行四次。第二个对一个id执行四个查询单元


如果没有索引,第一个应该更快—如果每次都需要从磁盘读取表,则速度应该是第二个的四倍。或者,如果表适合可用内存,并且后续扫描使用的是热数据页缓存,则会以增量方式加快扫描速度。

第一次扫描速度会更快。您可以通过分析查看它:

mysql> SET profiling = 1;
mysql> select * from bigtable where id in (200, 900, 22000, 88888);
mysql> select * from bigtable where id =200
-> union all
-> select * from bigtable where id =900
-> union all
-> select * from bigtable where id =22000
-> union all
-> select * from bigtable where id =88888;
mysql> show profile for query 1;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000046 |
| checking permissions | 0.000006 |
| Opening tables       | 0.000013 |
| init                 | 0.000024 |
| System lock          | 0.000008 |
| optimizing           | 0.000009 |
| statistics           | 0.000031 |
| preparing            | 0.000010 |
| executing            | 0.000003 |
| Sending data         | 0.000072 |
| end                  | 0.000004 |
| query end            | 0.000006 |
| closing tables       | 0.000006 |
| freeing items        | 0.000013 |
| cleaning up          | 0.000008 |
+----------------------+----------+
15 rows in set, 1 warning (0,00 sec)

mysql> show profile for query 2;
+----------------------+----------+                                                                                                                                 
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000054 |
| checking permissions | 0.000006 |
| checking permissions | 0.000002 |
| checking permissions | 0.000003 |
| checking permissions | 0.000004 |
| Opening tables       | 0.000112 |
| init                 | 0.000058 |
| System lock          | 0.000009 |
| optimizing           | 0.000008 |
| statistics           | 0.000032 |
| preparing            | 0.000009 |
| optimizing           | 0.000005 |
| statistics           | 0.000017 |
| preparing            | 0.000005 |
| optimizing           | 0.000005 |
| statistics           | 0.000014 |
| preparing            | 0.000005 |
| optimizing           | 0.000005 |
| statistics           | 0.000014 |
| preparing            | 0.000006 |
| executing            | 0.000003 |
| Sending data         | 0.000018 |
| executing            | 0.000003 |
| Sending data         | 0.000008 |
| executing            | 0.000003 |
| Sending data         | 0.000007 |
| executing            | 0.000003 |
| Sending data         | 0.000007 |
| end                  | 0.000004 |
| query end            | 0.000007 |
| removing tmp table   | 0.000009 |
| query end            | 0.000002 |
| closing tables       | 0.000008 |
| freeing items        | 0.000020 |
| cleaning up          | 0.000011 |
+----------------------+----------+
35 rows in set, 1 warning (0,00 sec)

因此,即使查询使用索引时实际执行速度很快,union内部单独查询的开销也是存在的。

Query2是Query1的四倍;但是MySQL在OR中的索引利用率相当差,并且基本上是一堆OR,这导致后者的查询通常执行得更快。但是,我听说它们有了很大的改进,所以这可能取决于执行查询的MySQL版本。另外,除非你有大量的用户;第一个查询的单表扫描可能仍然比第二个查询的四个索引查找快。不一定是真的:如果状态列上有索引,第二个查询将执行索引扫描4次。不一定比第一次查询慢。但是,我不能给出第二个查询更快的例子。
(SELECT id FROM users WHERE status = 1)
UNION ALL
(SELECT id FROM users WHERE status = 6)
UNION ALL
(SELECT id FROM users WHERE status = 11)
UNION ALL
(SELECT id FROM users WHERE status = 13)
mysql> SET profiling = 1;
mysql> select * from bigtable where id in (200, 900, 22000, 88888);
mysql> select * from bigtable where id =200
-> union all
-> select * from bigtable where id =900
-> union all
-> select * from bigtable where id =22000
-> union all
-> select * from bigtable where id =88888;
mysql> show profile for query 1;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000046 |
| checking permissions | 0.000006 |
| Opening tables       | 0.000013 |
| init                 | 0.000024 |
| System lock          | 0.000008 |
| optimizing           | 0.000009 |
| statistics           | 0.000031 |
| preparing            | 0.000010 |
| executing            | 0.000003 |
| Sending data         | 0.000072 |
| end                  | 0.000004 |
| query end            | 0.000006 |
| closing tables       | 0.000006 |
| freeing items        | 0.000013 |
| cleaning up          | 0.000008 |
+----------------------+----------+
15 rows in set, 1 warning (0,00 sec)

mysql> show profile for query 2;
+----------------------+----------+                                                                                                                                 
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000054 |
| checking permissions | 0.000006 |
| checking permissions | 0.000002 |
| checking permissions | 0.000003 |
| checking permissions | 0.000004 |
| Opening tables       | 0.000112 |
| init                 | 0.000058 |
| System lock          | 0.000009 |
| optimizing           | 0.000008 |
| statistics           | 0.000032 |
| preparing            | 0.000009 |
| optimizing           | 0.000005 |
| statistics           | 0.000017 |
| preparing            | 0.000005 |
| optimizing           | 0.000005 |
| statistics           | 0.000014 |
| preparing            | 0.000005 |
| optimizing           | 0.000005 |
| statistics           | 0.000014 |
| preparing            | 0.000006 |
| executing            | 0.000003 |
| Sending data         | 0.000018 |
| executing            | 0.000003 |
| Sending data         | 0.000008 |
| executing            | 0.000003 |
| Sending data         | 0.000007 |
| executing            | 0.000003 |
| Sending data         | 0.000007 |
| end                  | 0.000004 |
| query end            | 0.000007 |
| removing tmp table   | 0.000009 |
| query end            | 0.000002 |
| closing tables       | 0.000008 |
| freeing items        | 0.000020 |
| cleaning up          | 0.000011 |
+----------------------+----------+
35 rows in set, 1 warning (0,00 sec)