'WHERE A=x' 和 'WHERE A IN (x)' 之间的成本差异?
Cost difference between 'WHERE A=x' and 'WHERE A IN (x)'?
如果我想查找给定字段等于某个值的记录,我使用
SELECT * from TableName WHERE FieldName=value;
如果我想 select 匹配值列表的记录,我可以使用
SELECT * from TableName WHERE FieldName IN (value1, value2, ..., valueN);
避免WHERE FieldName = value1 OR FieldName = value2 OR...
(已编辑,因为这似乎误导了问题的目的)
使用.eqp on
似乎表明当我的列表只包含一个元素时,这两个查询是等价的。
这是真的吗?
如果是这样,我可以自由使用 WHERE FieldName IN (...)
并将值解析为逗号分隔列表(避免尾随逗号等)而不增加查询成本吗?
这似乎会大大简化我的查询编码,但令我惊讶的是 IN
运算符没有额外的复杂性成本,无论列表是否只有一个元素。
Edit:明确地说,我不会在任何情况下使用 OR
- 如果我有一个值,那么之前我一直在使用第一种形式(FieldName=value
)。如果我有多个值,我会使用 IN (val1, val2, ...)
。根据评论,我似乎可以删除处理这些代码所需的代码,而只搜索 IN (value1)
.
当 SQLite 估计 IN 列表太短以至于其开销大于 OR-connected 系列相等比较的开销时,它将查询转换为后一种形式。
目前,这是针对大小为 1 或 2 的 IN 列表完成的。
如EXPLAIN所示,单项代码相同:
sqlite> explain select * from t where x = 1;
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 10 0 00 Start at 10
1 OpenRead 0 2 0 1 00 root=2 iDb=0; t
2 Rewind 0 8 0 00
3 Column 0 0 1 00 r[1]=t.x
4 Ne 2 7 1 (BINARY) 51 if r[1]!=r[2] goto 7
5 Copy 1 3 0 00 r[3]=r[1]
6 ResultRow 3 1 0 00 output=r[3]
7 Next 0 3 0 01
8 Close 0 0 0 00
9 Halt 0 0 0 00
10 Transaction 0 0 1 0 01 usesStmtJournal=0
11 TableLock 0 2 0 t 00 iDb=0 root=2 write=0
12 Integer 1 2 0 00 r[2]=1
13 Goto 0 1 0 00
sqlite> explain select * from t where x in (1);
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 10 0 00 Start at 10
1 OpenRead 0 2 0 1 00 root=2 iDb=0; t
2 Rewind 0 8 0 00
3 Column 0 0 1 00 r[1]=t.x
4 Ne 2 7 1 (BINARY) 51 if r[1]!=r[2] goto 7
5 Copy 1 3 0 00 r[3]=r[1]
6 ResultRow 3 1 0 00 output=r[3]
7 Next 0 3 0 01
8 Close 0 0 0 00
9 Halt 0 0 0 00
10 Transaction 0 0 1 0 01 usesStmtJournal=0
11 TableLock 0 2 0 t 00 iDb=0 root=2 write=0
12 Integer 1 2 0 00 r[2]=1
13 Goto 0 1 0 00
(如果 OR 项太多,SQLite 也会执行 opposite transformation。)
如果我想查找给定字段等于某个值的记录,我使用
SELECT * from TableName WHERE FieldName=value;
如果我想 select 匹配值列表的记录,我可以使用
SELECT * from TableName WHERE FieldName IN (value1, value2, ..., valueN);
避免
(已编辑,因为这似乎误导了问题的目的)WHERE FieldName = value1 OR FieldName = value2 OR...
使用.eqp on
似乎表明当我的列表只包含一个元素时,这两个查询是等价的。
这是真的吗?
如果是这样,我可以自由使用 WHERE FieldName IN (...)
并将值解析为逗号分隔列表(避免尾随逗号等)而不增加查询成本吗?
这似乎会大大简化我的查询编码,但令我惊讶的是 IN
运算符没有额外的复杂性成本,无论列表是否只有一个元素。
Edit:明确地说,我不会在任何情况下使用 OR
- 如果我有一个值,那么之前我一直在使用第一种形式(FieldName=value
)。如果我有多个值,我会使用 IN (val1, val2, ...)
。根据评论,我似乎可以删除处理这些代码所需的代码,而只搜索 IN (value1)
.
当 SQLite 估计 IN 列表太短以至于其开销大于 OR-connected 系列相等比较的开销时,它将查询转换为后一种形式。 目前,这是针对大小为 1 或 2 的 IN 列表完成的。
如EXPLAIN所示,单项代码相同:
sqlite> explain select * from t where x = 1; addr opcode p1 p2 p3 p4 p5 comment ---- ------------- ---- ---- ---- ------------- -- ------------- 0 Init 0 10 0 00 Start at 10 1 OpenRead 0 2 0 1 00 root=2 iDb=0; t 2 Rewind 0 8 0 00 3 Column 0 0 1 00 r[1]=t.x 4 Ne 2 7 1 (BINARY) 51 if r[1]!=r[2] goto 7 5 Copy 1 3 0 00 r[3]=r[1] 6 ResultRow 3 1 0 00 output=r[3] 7 Next 0 3 0 01 8 Close 0 0 0 00 9 Halt 0 0 0 00 10 Transaction 0 0 1 0 01 usesStmtJournal=0 11 TableLock 0 2 0 t 00 iDb=0 root=2 write=0 12 Integer 1 2 0 00 r[2]=1 13 Goto 0 1 0 00 sqlite> explain select * from t where x in (1); addr opcode p1 p2 p3 p4 p5 comment ---- ------------- ---- ---- ---- ------------- -- ------------- 0 Init 0 10 0 00 Start at 10 1 OpenRead 0 2 0 1 00 root=2 iDb=0; t 2 Rewind 0 8 0 00 3 Column 0 0 1 00 r[1]=t.x 4 Ne 2 7 1 (BINARY) 51 if r[1]!=r[2] goto 7 5 Copy 1 3 0 00 r[3]=r[1] 6 ResultRow 3 1 0 00 output=r[3] 7 Next 0 3 0 01 8 Close 0 0 0 00 9 Halt 0 0 0 00 10 Transaction 0 0 1 0 01 usesStmtJournal=0 11 TableLock 0 2 0 t 00 iDb=0 root=2 write=0 12 Integer 1 2 0 00 r[2]=1 13 Goto 0 1 0 00
(如果 OR 项太多,SQLite 也会执行 opposite transformation。)