1

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

Select something Where foo=1 

...和...

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

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

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

为多个项目 (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)
4

2 回答 2

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 部分留给其他人 :)

于 2012-12-10T11:49:48.020 回答
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)
于 2012-12-12T10:11:39.967 回答