Sql 如何在Postgres/Rails中禁用或条件优化

Sql 如何在Postgres/Rails中禁用或条件优化,sql,ruby-on-rails,postgresql,Sql,Ruby On Rails,Postgresql,我有一个名为a的模型,其中包含列col和col2。col1具有唯一索引。(我正在使用Postgres数据库。) 让我们尝试在col2或col1中找到与给定值匹配的第一行 a = A.first(:conditions=> ["col2 = :id OR col1 = :id", {:id => 3}]) # select * from A where (col2 = 3 OR col1 = 3) LIMIT 1 上面的SQL返回第2行,而不是第1行。我怀疑查询优化器选择首先执行co

我有一个名为
a
的模型,其中包含列
col
col2
col1
具有唯一索引。(我正在使用Postgres数据库。)

让我们尝试在
col2
col1
中找到与给定值匹配的第一行

a = A.first(:conditions=> ["col2 = :id OR col1 = :id", {:id => 3}])
# select * from A where (col2 = 3 OR col1 = 3) LIMIT 1
上面的SQL返回第2行,而不是第1行。我怀疑查询优化器选择首先执行
col1=3
,因为
col1
具有唯一索引


如何覆盖此行为?我如何指示Postgres optimizer使用或条件的现有顺序?

似乎您不能,请使用case语句:

以这种方式使用的CASE构造将挫败优化尝试,因此只应在必要时进行


如果您没有指定明确的顺序,那么第一行就没有任何意义;当然,特定时间特定查询的结果集将有第一行,但不能保证使用相同数据再次运行相同查询将产生相同的第一行。关系数据库中的表没有顺序,因此根本没有指定的现有顺序。你做了一个错误的假设;该实现可以通过磁盘上的PK隐式地对记录排序,但不能保证这一点,也不能保证下一个版本的行为相同;此外,不能保证数据库将以磁盘顺序返回行,除非您使用ORDERBY子句指定了特定的顺序,否则数据库可以按照它想要的任何方式对行进行排序

如果您想要订单,那么您应该包括ORDERBY子句;你可能想要更像这样的东西:

a = A.where("col2 = :id OR col1 = :id", {:id => 3}).order(:id).first
如果您想在查看
col1
之前查看
col2
,那么您应该这样说:

a =  A.where('col2 = :id', :id => 3).order(:id).first \
  || A.where('col1 = :id', :id => 3).order(:id).first

col2=:id或col1=:id
col1=:id或col2=:id
是等效的布尔表达式,因此数据库可以在,或者同时作为
col1=:id
,它可以按照自己喜欢的任何顺序自由访问行。

您仍然无法保证首先计算col2=:id。仍然有可能先计算col1=:id,对吗?与之相比,Postgres尤其如此MySQL@daniel:我也不认为对列顺序有任何保证,数据库可以自由地重新排列WHERE子句(只要结果相同)。如果你想让任何事情以任何特定的顺序发生,那么你必须手动安排。+1,在我当前的解决方案中,与你建议的类似(即管道结果)。我没有想到我会返回两行。应该是显而易见的。谢谢
a = A.where("col2 = :id OR col1 = :id", {:id => 3}).order(:id).first
a =  A.where('col2 = :id', :id => 3).order(:id).first \
  || A.where('col1 = :id', :id => 3).order(:id).first