sql >> Database >  >> RDS >> PostgreSQL

Snel vergelijkbare strings vinden met PostgreSQL

Zoals je het hebt, moet de overeenkomst tussen elk element en elk ander element van de tabel worden berekend (bijna een cross-join). Als uw tabel 1000 rijen heeft, zijn dat al 1.000.000 (!) gelijkenisberekeningen, vóór die kunnen worden vergeleken met de conditie en gesorteerd. Weegt vreselijk.

Gebruik SET pg_trgm.similarity_threshold en de % exploitant in plaats daarvan. Beide worden geleverd door de pg_trgm module. Op deze manier kan een trigram GiST-index met groot effect worden gebruikt.

De configuratieparameter pg_trgm.similarity_threshold vervangen van de functies set_limit() en show_limit() in Postgres 9.6. De verouderde functies werken nog steeds (vanaf Postgres 13). Ook zijn de prestaties van GIN- en GiST-indexen in veel opzichten verbeterd sinds Postgres 9.1.

Probeer in plaats daarvan:

SET pg_trgm.similarity_threshold = 0.8;  -- Postgres 9.6 or later
  
SELECT similarity(n1.name, n2.name) AS sim, n1.name, n2.name
FROM   names n1
JOIN   names n2 ON n1.name <> n2.name
               AND n1.name % n2.name
ORDER  BY sim DESC;

Sneller in orde van grootte, maar nog steeds traag.

pg_trgm.similarity_threshold is een "aangepaste" optie, die kan worden behandeld als elke andere optie. Zie:

  • Een parameter opvragen (instelling postgresql.conf) zoals "max_connections"

Misschien wilt u het aantal mogelijke paren beperken door voorwaarden toe te voegen (zoals overeenkomende eerste letters) voor cross-joining (en ondersteun dat met een bijpassende functionele index). De uitvoering van een cross join verslechtert met O(N²) .

Dit werkt niet omdat u niet kunt verwijzen naar uitvoerkolommen in WHERE of HAVING clausules:

WHERE ... sim > 0.8

Dat is volgens de SQL-standaard (die door bepaalde andere RDBMS nogal losjes wordt behandeld). Aan de andere kant:

ORDER BY sim DESC

Werkt omdat uitvoerkolommen kunnen worden gebruikt in GROUP BY en ORDER BY . Zie:

  • PostgreSQL hergebruikt berekeningsresultaat in selectiequery

Testcase

Ik heb een snelle test uitgevoerd op mijn oude testserver om mijn claims te verifiëren.
PostgreSQL 9.1.4. Tijden genomen met EXPLAIN ANALYZE (best of 5).

CREATE TEMP table t AS 
SELECT some_col AS name FROM some_table LIMIT 1000;  -- real life test strings

Eerste testronde met GIN-index:

CREATE INDEX t_gin ON t USING gin(name gin_trgm_ops);  -- round1: with GIN index

Tweede testronde met GIST-index:

DROP INDEX t_gin;
CREATE INDEX t_gist ON t USING gist(name gist_trgm_ops);

Nieuwe zoekopdracht:

SELECT set_limit(0.8);

SELECT similarity(n1.name, n2.name) AS sim, n1.name, n2.name
FROM   t n1
JOIN   t n2 ON n1.name <> n2.name
           AND n1.name % n2.name
ORDER  BY sim DESC;

GIN-index gebruikt, 64 hits:totale runtime:484.022 ms
GIST-index gebruikt, 64 hits:totale runtime:248.772 ms

Oude zoekopdracht:

SELECT (similarity(n1.name, n2.name)) as sim, n1.name, n2.name
FROM   t n1, t n2
WHERE  n1.name != n2.name
AND    similarity(n1.name, n2.name) > 0.8
ORDER  BY sim DESC;

GIN-index niet gebruikt, 64 hits:totale runtime:6345.833 ms
GIST-index niet gebruikt, 64 hits:totale looptijd:6335.975 ms

Anders identieke resultaten. Advies is goed. En dit is voor slechts 1000 rijen !

GIN of GiST?

GIN biedt vaak superieure leesprestaties:

  • Verschil tussen GiST en GIN-index

Maar niet in dit specifieke geval!

Dit kan vrij efficiënt worden geïmplementeerd door GiST-indexen, maar niet door GIN-indexen.

  • Meerkolomsindex op 3 velden met heterogene gegevenstypen



  1. SQLite heeft een foutcode van 14 . geretourneerd

  2. Prestaties stimuleren in een hybride cloudconfiguratie

  3. Afbeeldingsgegevens laden in BLOB-kolommen in Oracle

  4. Hoe gebruik ik variabelen in Oracle SQL Developer?