Запрос с UNION или ИЛИ? - PullRequest
0 голосов
/ 17 мая 2018

У меня есть таблица friend, используемая для хранения отношений между двумя пользователями.

Например: (1,2) означает, что user1 и user2 являются друзьями. (2,1) означает то же самое, но там мы не будем хранить это, делая uid1 < uid2 вручную:

CREATE TABLE public.friend (
  uid1 INTEGER,
  uid2 INTEGER
);
CREATE INDEX index_uid1 ON friend USING BTREE (uid1);
CREATE INDEX index_uid2 ON friend USING BTREE (uid2);

Чтобы найти друзей uid=2, я могу использовать:

SQL1:

select * from friend where uid1=2
union
select * from friend where uid2=2;

SQL2:

select * from friend uid1=2 or uid2=2

Что я получаю, так это то, что sql2 лучше, чем sql1 по производительности.

Но sql1 рекомендуется. Это правильно?

Ответы [ 3 ]

0 голосов
/ 17 мая 2018

union - накладные расходы на удаление дубликатов.Возможно, наиболее эффективным методом для запроса является:

select f.* from friend f where uid1 = 2
union all
select f.* from friend f where uid2 = 2 and uid1 <> 2;

В частности, это может использовать преимущества индексов f(uid1) и f(uid2).Ваша вторая версия, вероятно, выполняет полное сканирование таблицы.

0 голосов
/ 17 мая 2018

У меня есть таблица friend, используемая для хранения отношений между двумя пользователями.

Например: (1,2) означает, что user1 и user2 являются друзьями.(2,1) означает то же самое, но там мы не будем хранить это, делая uid1 < uid2 вручную:

Как правило, вы реализуете это с включенным PRIMARY KEY(udi1, uid2) и ограничение CHECK принудительное применение uid1 < uid2.

CREATE TABLE public.friend (
   uid1 integer
 , uid2 integer
 , PRIMARY KEY (uid1, uid2)
 , CONSTRAINT uid2_gt_uid1 CHECK (uid1 < uid2)
);

CREATE INDEX index_uid2 ON friend USING BTREE (uid2);

Вам не нужен другой индекс, он покрывается индексом PK;

<strike>CREATE INDEX index_uid1 ON friend USING BTREE (uid1);</strike>

Тогда не может быть дубликатов (включая переключенные дубликаты), и никто не может быть другом с самим собой, и ваш запрос может быть просто:

SELECT * FROM friend WHERE 2 IN (uid1, uid2);

... что означает:

SELECT * FROM friend WHERE uid1 = 2 OR uid2 = 2;

И вариант UNION теперь логически идентичен:

SELECT * FROM friend WHERE uid1=2
UNION
SELECT * FROM friend WHERE uid2=2;

Но вы бы UNION ALL вместо просто UNION, так как для начала нет дубликатов и UNION ALL дешевле.Но все же немного дороже, чем один SELECT выше.

Дубликаты?

В UNION ALL имеется три возможных источников дубликатов* query:

  1. Дублирующиеся строки в базовой таблице (исключены PK).
  2. Строки выбираются несколько раз болеечем одна SELECT ветвь.
  3. В вашем конкретном случае: логический дублируется с переключенными идентификаторами (исключено ограничением CHECK).

Как только вы поймете это, вы также поймете значение различных методов запросов.При предложенной настройке в качестве возможной проблемы остается только 2..

0 голосов
/ 17 мая 2018

Технически они не одинаковы, оператор объединения удалит дубликаты, а во втором примере нет.

...