Bar*_*ski 24 python sql sqlalchemy
我发现SQLAlchemy翻译了
db.query(...).filter(A.id.in_(ids))
Run Code Online (Sandbox Code Playgroud)
成
SELECT ...
FROM a
WHERE a.id != a.id
Run Code Online (Sandbox Code Playgroud)
如果ids
是空的 这导致在a
桌面上进行顺序扫描,这对性能来说显然是灾难性的.
第一个问题是:为什么?为什么不只是1 = 0
或任何不需要顺序扫描?
第二个,更重要的是:是否有一个常用的解决方法(除了if
几乎每个in_
)?
我想这in_
不能轻易地重新实现,以涵盖所有情况而不会导致这个问题,但我不能成为第一个面对它,可能有一些解决方案涵盖简单,常见的用例in_
.
SQLAlchemy每次发生时都会记录一条警告:
"The IN-predicate on 'foo.bar' was invoked with an empty sequence. This results in a contradiction, which nonetheless can be expensive to evaluate. Consider alternative strategies for improved performance."
我正在使用:
if len(ids) > 0:
db.query(...).where(A.id.in_(ids))
else:
db.query(...).where(False)
Run Code Online (Sandbox Code Playgroud)
我尝试过.limit(0)
而不是.where(false)
没有成功.空查询集中存在一些幕后的差异,这些差异打破了管道中的其他内容.这种解决方法虽然可能更快,但至少可以避免您提到的警告.
要回答OP关于"为什么"的问题,这里是FAQ条目(我总是很难找到):
为什么
.col.in_([])
生产col != col
?为什么不1=0
呢?对该问题的一点介绍.
IN
SQL中的运算符给出了要与列进行比较的元素列表,通常不接受空列表,也就是说有效说:Run Code Online (Sandbox Code Playgroud)column IN (1, 2, 3)
这是无效的说:
Run Code Online (Sandbox Code Playgroud)column IN ()
SQLAlchemy的
Operators.in_()
运算符在给定空列表时会生成以下表达式:Run Code Online (Sandbox Code Playgroud)column != column
从版本0.6开始,它还会产生一个警告,指出将会呈现效率较低的比较操作.此表达式是唯一一个既与数据库无关又能产生正确结果的表达式.
例如,"仅通过比较1 = 0或1!= 1来评估为假"的简单方法不能正确处理空值.一个表达式:
Run Code Online (Sandbox Code Playgroud)NOT column != column
不会返回一行
column IS NULL
,而是一个不考虑列的表达式,例如:Run Code Online (Sandbox Code Playgroud)NOT 1=0
将返回一行.
正如所示这篇文章,你可以使用任何功能,避免这种情况,因为它是语法上有效的甚至是空列表(但不支持SQLite的明显).对于大型列表来说,它可能更快,因为它可以减少字符串修改以构建查询.
最近修复了in_
运算符的性能问题,修复可能在SQLAlchemy 1.2.0中.
请注意您的要求:
A.id
具有可比性时,任何比较才能真正成功。不存在的值无法与任何东西进行比较,所有比较都会产生一个不存在的值,该值又被评估为False。也就是说, if A.ID
is NULL
thenA.ID == anything
是False并且A.ID != anything
is 也是False:A.ID == A.ID || A.ID != A.ID
is False if A.ID
is NULL
。IN
询问该值是否是空列表的一部分。不存在的值不属于任何列表,甚至不属于空列表。IS NOT NULL
并且是虚无的一部分。这是必须检查的情况。不存在的价值不是某种东西,而是某种东西。只有某些值不能NULL
成为空列表的成员...IN
如果序列为空,您可能应该删除- 子句。对于一个具体的例子这个sqlfiddle
对于更哲学的方法,请参阅空的本质是什么
归档时间: |
|
查看次数: |
7207 次 |
最近记录: |