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

Бързо намиране на подобни низове с PostgreSQL

По начина, по който го имате, трябва да се изчисли приликата между всеки елемент и всеки друг елемент от таблицата (почти кръстосано съединение). Ако таблицата ви има 1000 реда, това вече е 1 000 000 (!) изчисления за сходство, преди те могат да бъдат проверени спрямо състоянието и сортирани. Ужасно мащабира.

Използвайте SET pg_trgm.similarity_threshold и % вместо това оператор. И двете се предоставят от pg_trgm модул. По този начин триграма GiST индекс може да се използва с голям ефект.

Конфигурационният параметър pg_trgm.similarity_threshold замени функциите set_limit() и show_limit() в Postgres 9.6. Оттеглените функции все още работят (от Postgres 13). Също така производителността на индексите GIN и GiST се подобри по много начини след Postgres 9.1.

Опитайте вместо това:

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;

По-бързо с порядък, но все пак бавно.

pg_trgm.similarity_threshold е "персонализирана" опция, която може да се обработва като всяка друга опция. Вижте:

  • Запитване за параметър (настройка postgresql.conf) като "max_connections"

Може да искате да ограничите броя на възможните двойки, като добавите предварителни условия (като съвпадение на първите букви) преди кръстосано свързване (и поддържа това със съвпадащ функционален индекс). Изпълнението на кръстосано съединение се влошава с O(N²) .

Товане работи защото не можете да се обърнете към изходни колони в WHERE или HAVING клаузи:

WHERE ... sim > 0.8

Това е според стандарта SQL (който се обработва доста слабо от някои други RDBMS). От друга страна:

ORDER BY sim DESC

Работи защото изходните колони могат да се използва в GROUP BY и ORDER BY . Вижте:

  • Повторното използване на PostgreSQL в резултат на изчисление в заявка за избор

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

Проведох бърз тест на стария си тестов сървър, за да потвърдя твърденията си.
PostgreSQL 9.1.4. Времена, взети с EXPLAIN ANALYZE (най-доброто от 5).

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

Първи кръг от тестове с GIN индекс:

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

Втори кръг от тестове с GIST индекс:

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

Нова заявка:

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, 64 посещения:общо време на изпълнение:484,022 мс
Използван индекс на GIST, 64 посещения:общо време на изпълнение:248,772 мс

Стара заявка:

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 индексне използван, 64 посещения:общо време на изпълнение:6345,833 мс
Индекс на GIST не използван, 64 посещения:общо време на изпълнение:6335,975 ms

Иначе резултати са идентични. Съветът е добър. И това е за само 1000 реда !

GIN или GiST?

GIN често осигурява превъзходна производителност на четене:

  • Разлика между GiST и GIN индекс

Но не в този конкретен случай!

Това може да се реализира доста ефективно от GiST индекси, но не и от GIN индекси.

  • Многоколонов индекс на 3 полета с разнородни типове данни



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да получа локални данни в база данни само за четене с помощта на dplyr?

  2. SQLAlchemy множество външни ключове в един съпоставен клас към същия първичен ключ

  3. Какво изисква този JavaScript?

  4. Как Atan2() работи в PostgreSQL

  5. Django моделира един външен ключ към много таблици