PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

SQL:Jeśli chodzi o NOT IN i NOT EQUAL TO, co jest wydajniejsze i dlaczego?

W PostgreSQL zwykle występuje niewielka różnica przy rozsądnych długościach list, chociaż IN jest znacznie czystszy koncepcyjnie. Bardzo długie AND ... <> ... listy i bardzo długie NOT IN wykazy obie działają fatalnie, z AND znacznie gorzej niż NOT IN .

W obu przypadkach, jeśli są one wystarczająco długie, abyś mógł zadać pytanie, powinieneś zamiast tego wykonać test blokujący łączenie lub wykluczanie podzapytań na liście wartości.

WITH excluded(item) AS (
    VALUES('item1'), ('item2'), ('item3'), ('item4'),('item5')
)
SELECT * 
FROM thetable t
WHERE NOT EXISTS(SELECT 1 FROM excluded e WHERE t.item = e.item);

lub:

WITH excluded(item) AS (
    VALUES('item1'), ('item2'), ('item3'), ('item4'),('item5')
)
SELECT * 
FROM thetable t
LEFT OUTER JOIN excluded e ON (t.item = e.item)
WHERE e.item IS NULL;

(W nowoczesnych wersjach Pg obie i tak wygenerują ten sam plan zapytań).

Jeśli lista wartości jest wystarczająco długa (wiele dziesiątek tysięcy elementów), analiza zapytań może zacząć mieć znaczny koszt. W tym momencie powinieneś rozważyć utworzenie TEMPORARY tabela, COPY danych, aby je wykluczyć, prawdopodobnie tworząc na nich indeks, a następnie stosując jedno z powyższych podejść w tabeli tymczasowej zamiast CTE.

Demo:

CREATE UNLOGGED TABLE exclude_test(id integer primary key);
INSERT INTO exclude_test(id) SELECT generate_series(1,50000);
CREATE TABLE exclude AS SELECT x AS item FROM generate_series(1,40000,4) x;

gdzie exclude to lista wartości do pominięcia.

Następnie porównuję następujące podejścia na tych samych danych ze wszystkimi wynikami w milisekundach:

  • NOT IN lista:3424.596
  • AND ... lista:80173.823
  • VALUES oparte JOIN wykluczenie:20.727
  • VALUES wykluczenie na podstawie podzapytania:20.495
  • Oparte na tabeli JOIN , brak indeksu na byłej liście:25.183
  • Na podstawie tabeli podzapytań, brak indeksu na byłej liście:23.985

... dzięki czemu podejście oparte na CTE jest ponad trzy tysiące razy szybsze niż AND listy i 130 razy szybciej niż NOT IN lista.

Kod tutaj:https://gist.github.com/ringerc/5755247 (chrońcie oczy, którzy podążacie za tym linkiem).

Dla tego rozmiaru zbioru danych dodanie indeksu na liście wykluczeń nie ma żadnego znaczenia.

Uwagi:

  • IN lista wygenerowana za pomocą SELECT 'IN (' || string_agg(item::text, ',' ORDER BY item) || ')' from exclude;
  • AND lista wygenerowana za pomocą SELECT string_agg(item::text, ' AND item <> ') from exclude; )
  • Wykluczanie podzapytań i tabel na podstawie złączeń było prawie takie samo w przypadku powtarzających się przebiegów.
  • Badanie planu pokazuje, że Pg tłumaczy NOT IN do <> ALL

Więc... widać, że jest naprawdę ogromny przerwa między IN i AND listy vs robienie prawidłowego sprzężenia. Zaskoczyło mnie to, jak szybko robię to z CTE przy użyciu VALUES lista była ... analizowała VALUES lista nie zajęła prawie wcale czasu, wykonując to samo lub nieco szybciej niż podejście tabeli w większości testów.

Byłoby miło, gdyby PostgreSQL mógł automatycznie rozpoznać niedorzecznie długi IN klauzula lub łańcuch podobnych AND warunków i przełącz się na inteligentniejsze podejście, takie jak zrobienie sprzężenia haszowanego lub niejawne przekształcenie go w węzeł CTE. W tej chwili nie wie, jak to zrobić.

Zobacz też:

  • ten przydatny post na blogu, który Magnus Hagander napisał na ten temat


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Błąd:Uwierzytelnianie peera nie powiodło się dla postgres użytkownika podczas próby uruchomienia pgsql działającego z szynami

  2. Jak debugować procedury składowane postgresql?

  3. Jak połączyć GraphQL i PostgreSQL

  4. Dlaczego powinieneś uczyć się PostgreSQL?

  5. Jak klastrować Odoo 12 za pomocą replikacji strumieniowej PostgreSQL w celu zapewnienia wysokiej dostępności?