PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Как да напиша съединение с този необичаен критерий за съвпадение?

Индекси

Създайте индекси на x.id и y.id - които вероятно вече имате, ако това са вашите първични ключове.
Индекс с няколко колони също може да помогне, особено с сканира само за индекс в стр. 9.2+:

CREATE INDEX y_mult_idx ON y (id DESC, val)

Въпреки това, в моите тестове, този индекс не беше използван в началото. Трябваше да добавя (иначе безсмислено) val към ORDER BY за да убеди планиращия заявки, че редът на сортиране съвпада. Вижте запитване 3 .

Индексът прави малка разлика в тази синтетична настройка. Но за таблици с повече колони, извличане на val от таблицата става все по-скъп, което прави "покриващия" индекс по-привлекателен.

Заявки

1) Просто

SELECT DISTINCT ON (x.id)
       x.id, y.val
FROM   x
JOIN   y ON y.id <= x.id
ORDER  BY x.id, y.id DESC;

SQL Fiddle.

Повече обяснение за техниката с DISTINCT в този свързан отговор:

Проведох някои тестове, защото имах подозрения, че първата заявка няма да се мащабира добре. Бързо е с малка маса, но не е добро с по-големи маси. Postgres не оптимизира плана и започва с (ограничено) кръстосано свързване с цена O(N²) .

2) Бързо

Тази заявка все още е доста проста и се мащабира отлично:

SELECT x.id, y.val
FROM   x
JOIN  (SELECT *, lead(id, 1, 2147483647) OVER (ORDER BY id) AS next_id FROM y) y
       ON  x.id >= y.id
       AND x.id <  y.next_id
ORDER  BY 1;

Прозоречната функция lead() е инструментален. Използвам опцията за предоставяне по подразбиране, за да покрия ъгловия регистър на последния ред:2147483647 е най-голямото възможно цяло число . Адаптиране към вашия тип данни.

3) Много просто и почти толкова бързо

SELECT x.id
     ,(SELECT val FROM y WHERE id <= x.id ORDER BY id DESC, val LIMIT 1) AS val
FROM   x;

Обикновено свързани подзаявки са склонни да бъдат бавни. Но този може просто да избере стойност от (покриващия) индекс и иначе е толкова прост, че може да се конкурира.

Допълнителният ORDER BY елемент val (удебелено подчертаване) изглежда безсмислено. Но добавянето му убеждава планиращия заявки, че е добре да се използва индексът с няколко колони y_mult_idx отгоре, защото редът на сортиране съвпада. Обърнете внимание на

в EXPLAIN изход.

Тестов случай

След оживен дебат и множество актуализации събрах всички запитвания, публикувани досега, и направих тестов случай за бърз преглед. Използвам само 1000 реда, така че SQLfiddle не изчаква с по-бавните заявки. Но първите 4 (Erwin 2, Clodoaldo, a_horse, Erwin 3) се мащабират линейно във всичките ми локални тестове. Актуализиран още веднъж, за да включва най-новото ми допълнение, подобряване на формата и подреждане по ефективност сега:

Голям SQL Fiddle сравняване на ефективността.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQLAlchemy, PostgreSQL и array_agg:Как да изберете елементи от array_agg?

  2. Колоната Postgres bytea връща низ (масив от символи) вместо масив от байтове

  3. Как да създавате и изтривате бази данни и таблици в PostgreSQL

  4. PostgreSQL дата C# DateTime

  5. psycopg2 cursor.execute() с параметър на SQL заявка причинява синтактична грешка