简单的问题。想知道长的IN子句是否是代码气味?我真的不知道如何证明这一点。我不能把手指放在为什么它闻起来不像我认为的那样。
select
name,
code,
capital,
population,
flower,
bird
from us_states
where
code in
('NJ', 'NY', 'PA', 'CA', 'AL', 'AK', 'AZ',
'IL', 'IN', 'KY', 'KS', 'DC', 'MD', 'MA')
数据库通常如何实现这样的查找?是一个临时表制作并加入?或者它只是扩展为一系列逻辑OR?
感觉它应该是一个加入......
我不是说所有的IN条款都不好。有时你无法帮助它。但是有些情况(特别是它们得到的时间越长),你所匹配的元素集合实际上来自某个地方。不应该加入吗?
是否值得创建(通过应用程序级别)一个临时表,其中包含您要搜索的所有元素,然后对其进行真正的连接?
select u.*
from us_states u
join #chosen_states t
on u.code = t.code
答案 0 :(得分:8)
我认为这是代码味道。首先,数据库对IN
子句中允许的元素数量有限制,如果动态生成SQL,最终可能会遇到这些限制。
当列表开始变长时,我会转换为使用带临时表的存储过程,以避免出现错误。
我怀疑性能是一个主要问题,IN
条款非常快,因为它们可以短路,与NOT IN
条款不同。
答案 1 :(得分:4)
是否值得(通过应用程序级别)创建临时表。
IN
的问题在于它不使用索引,并且对源表中的每一行重复比较(最差情况:此处为x14)。
如果在连接字段上添加索引,则创建临时表是个好主意
这样查询可以使用BTree索引直接查找值,该索引应该只进行3或4次比较最坏情况log2(14)= 3.something
哪个更快。
如果你很聪明,你甚至可以使用hash-index
,在这种情况下,数据库只需要进行1次比较,与btree索引相比,你的查询速度提高了3倍。
使用临时表的提示
确保使用内存表
使用hash index
作为主键
尝试在一个语句中执行插入操作。
由于使用哈希索引进行O(1)查找时间,因此加速创建temp-table的半常数时间会相形见绌。
答案 2 :(得分:0)
我不知道这是代码味道,确切地说。有时你只有很长的事情in
列出你可能存在的事情。
至于制作一个带有元素的临时表(甚至是一个查找表)并加入反对(甚至做一个where [column] in (select [lookup] from [lookuptable])
是我喜欢的方法之一IFF * a)有大量的值b)如果有的话,很少会改变。
*:“If and Only If”
答案 3 :(得分:0)
您也可以使用带有IN的子查询,如here in the manual所述。
SELECT * FROM us_states WHERE code IN (SELECT code FROM state_codes);
答案 4 :(得分:0)
我也认为它是“嗅觉”。对于不经意的观察者来说,IN
条款可能类似于集合,列表,包,表等,但不是。
根据SQL标准,您的IN
子句仅仅是
(
code = 'NJ' OR code = 'NY' OR code = 'PA' OR code = 'CA'
OR code = 'AL' OR code = 'AK' OR code = 'AZ'
OR code = 'IL' OR code = 'IN' OR code = 'KY'
OR code = 'KS' OR code = 'DC' OR code = 'MD'
OR code = 'MA'
)
我希望典型的解析器能够以这种方式扩展IN
子句;我知道SQL Server的作用,因为当我在INFORMATION_SCHEMA中检查约束的定义时,我用来创建某些IN
约束的漂亮,整洁的CHECK
子句变成了一组丑陋的OR
子句。 YMMV:如果你担心性能,请测试。
有一个设计经验法则规定,如果值集很小且稳定,则使用IN
子句,否则使用表。 52个中的14个是“小”是主观的。小表是否最佳索引可能取决于它与其他表的连接方式:this SO question可能是一个有用的参考。