Как отключить оптимизацию условий OR в Postgres / Rails - PullRequest
2 голосов
/ 19 декабря 2011

У меня есть модель с именем A со столбцами col и col2. col1 имеет уникальный индекс. (Я использую базу данных Postgres.)

class A < ActiveRecord::Base
  # id, col1, col2
end

Данные:

id  col1   col2
==  ====   ====
1   2       3
2   3       4

Попробуем найти первую строку, соответствующую данному значению в 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 использовать существующий заказ для условия ИЛИ?

Ответы [ 2 ]

5 голосов
/ 19 декабря 2011

Если вы не укажете явный порядок, тогда первая строка не имеет никакого смысла;набор результатов из определенного запроса в определенный момент времени, конечно, будет иметь первую строку, но нет гарантии, что повторный запуск того же запроса с теми же данными приведет к той же первой строке.Таблицы в реляционной базе данных не упорядочены, поэтому нет указанного существующего порядка .Вы делаете плохое предположение;реализация может неявно упорядочивать записи PK на диске, но это не гарантирует и не гарантирует, что следующая версия будет вести себя так же;Более того, нет никакой гарантии, что база данных будет возвращать строки в порядке дисков, база данных может свободно упорядочивать строки любым удобным для нее способом, если только вы не указали конкретный порядок с помощью предложения ORDER BY.

Еслиесли вы хотите заказать, вы должны включить предложение ORDER BY;Вы, вероятно, хотите что-то более похожее на это:

a = A.where("col2 = :id OR col1 = :id", {:id => 3}).order(:id).first

И если вы хотите посмотреть на col2 до col1, то вам следует сказать так:

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

col2 = :id OR col1 = :id иcol1 = :id OR col2 = :id являются эквивалентными логическими выражениями, поэтому база данных может свободно проверять col2 = :id до, после или одновременно с col1 = :id, и имеет свободный доступ к строкам в любом порядке.

1 голос
/ 19 декабря 2011

Кажется, вы не можете, используйте регистр:

http://www.postgresql.org/docs/current/static/sql-expressions.html#SYNTAX-EXPRESS-EVAL

Конструкция CASE, используемая таким образом, будет препятствовать попыткам оптимизации, поэтому она должна выполняться только при необходимости

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...