Mysql(和Postgresql)在where = 1和in(1)中的表现

时间:2012-12-10 10:21:52

标签: mysql sql ruby-on-rails-3 postgresql activerecord

出于好奇,有人知道你做的时候是否有任何重大的性能差异......

Select something Where foo=1 

......和......

Select something Where foo In(1)    #just one item not multiple

...单个或联合SQL查询中的Mysql和Postgresql。

问题是我正在构建Ruby on Rails scopes,我想知道哪种方法更好,

为多个项目(IN)创建一个范围,为使用相等(=)

的单个项目创建一个范围
scope :with_owner_ids, lambda{|owner_class, *ids| where(owner_type: owner_class.model_name, owner_id: ids.flatten)}
scope :with_owner, lambda{|owner| where(owner_type: owner.class.model_name, owner_id: owner.id)}
#... where `foos`.`owner_class`='User' and `foos`.`owner_id` = 15

或更清洁,为多个项目(IN)创建范围,而不是将此范围传递给单个项目的另一个范围(IN也是如此)

scope :with_owner_ids, lambda{|owner_class, *ids| where(owner_type: owner_class.model_name, owner_id: ids.flatten)}
scope :with_owner, lambda{|owner| with_owner_ids(owner.class, owner.id)}
#... where `foos`.`owner_class`='User' and `foos`.`owner_id` IN (15)

2 个答案:

答案 0 :(得分:4)

一个非常简单的表上的PostgreSQL示例:

CREATE TABLE a (
    a_id integer
    , t_id integer
);

COPY a
FROM STDIN;
1   1
2   1
3   1
4   4
\.

EXPLAIN ANALYZE SELECT * FROM a WHERE t_id IN (1);

 Seq Scan on a  (cost=0.00..36.75 rows=11 width=8) (actual time=0.056..0.059 rows=3 loops=1)
   Filter: (t_id = 1)
 Total runtime: 41.795 ms

Filter: (t_id = 1)部分可以清楚地看出IN (1)被翻译成一个简单的等式检查,因此这两种形式没有区别。

我将MySQL部分留给其他人:)

答案 1 :(得分:0)

我玩过MySQL EXPLAIN:

<强>等于

mysql> explain extended select * from document_name_ownerships as dno join document_names as dn on dn.id = dno.document_name_id  where dn.id = 18 ;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | dn    | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 |             |
|  1 | SIMPLE      | dno   | ALL   | NULL          | NULL    | NULL    | NULL  |   81 |   100.00 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+----------+-------------+
2 

rows in set, 1 warning (0.00 sec)

<强>在()

mysql> explain extended select * from document_name_ownerships as dno join document_names as dn on dn.id = dno.document_name_id  where dn.id in(18) ;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | dn    | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 |             |
|  1 | SIMPLE      | dno   | ALL   | NULL          | NULL    | NULL    | NULL  |   81 |   100.00 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+----------+-------------+
2 rows in set, 1 warning (0.01 sec)

因此,当涉及到一条记录时,等于(=)似乎比 IN()快得多

但有趣的是,当我完成几个项目时,结果是相同的:

mysql> explain extended select * from document_name_ownerships as dno join document_names as dn on dn.id = dno.document_name_id  where dn.id = 18 or dn.id=17  or dn.id=19;
> (0.00 sec)

mysql> explain extended select * from document_name_ownerships as dno join document_names as  dn on dn.id = dno.document_name_id  where dn.id in (18, 17, 19);
> (0.00 sec)

但不知道这个结果是否可以在实时服务器上受到信任,因为在我的开发机器上我有SSD驱动器......但对我来说似乎是一样的


<强>更新

有70000条记录

select * from document_name_ownerships as dno join document_names as dn on dn.id = dno.document_name_id  where dn.id = 60811;
1 row in set (0.04 sec)

select * from document_name_ownerships as dno join document_names as dn on dn.id = dno.document_name_id  where dn.id in( 60811);
1 row in set (0.04 sec)

多个

select * from document_name_ownerships as dno join document_names as dn on dn.id = dno.document_name_id  where dn.id in( 60800, 11111, 22222, 40000);
4 rows in set (0.07 sec)

select * from document_name_ownerships as dno join document_names as dn on dn.id = dno.document_name_id  where dn.id = 60800 or dn.id = 11111 or dn.id = 22222 or dn.id = 40000;
4 rows in set (0.08 sec)