PostgreSQL Antipatterns: сказ ΠΎΠ± ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠΉ Π΄ΠΎΡ€Π°Π±ΠΎΡ‚ΠΊΠ΅ поиска ΠΏΠΎ названию, ΠΈΠ»ΠΈ Β«ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ Ρ‚ΡƒΠ΄Π° ΠΈ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΒ»

Высячи ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€ΠΎΠ² ΠΈΠ· офисов ΠΏΡ€ΠΎΠ΄Π°ΠΆ ΠΏΠΎ всСй странС Ρ„ΠΈΠΊΡΠΈΡ€ΡƒΡŽΡ‚ Π² нашСй CRM-систСмС Π΅ΠΆΠ΅Π΄Π½Π΅Π²Π½ΠΎ дСсятки тысяч ΠΊΠΎΠ½Ρ‚Π°ΠΊΡ‚ΠΎΠ² β€” Ρ„Π°ΠΊΡ‚ΠΎΠ² общСния с ΠΏΠΎΡ‚Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΌΠΈ ΠΈΠ»ΠΈ ΡƒΠΆΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‰ΠΈΠΌΠΈ с Π½Π°ΠΌΠΈ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°ΠΌΠΈ. А для этого ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° Π½Π°Π΄ΠΎ сначала Π½Π°ΠΉΡ‚ΠΈ, ΠΈ ΠΆΠ΅Π»Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ ΠΎΡ‡Π΅Π½ΡŒ быстро. И происходит это Ρ‡Π°Ρ‰Π΅ всСго ΠΏΠΎ названию.

ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ Π½Π΅ΡƒΠ΄ΠΈΠ²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ, Ρ‡Ρ‚ΠΎ, разбирая Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄Π½ΠΎΠΉ Ρ€Π°Π· «тяТСлыС» запросы Π½Π° ΠΎΠ΄Π½ΠΎΠΉ ΠΈΠ· самых Π½Π°Π³Ρ€ΡƒΠΆΠ΅Π½Π½Ρ‹Ρ… Π±Π°Π· β€” нашСго собствСнного ΠΊΠΎΡ€ΠΏΠΎΡ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠ³ΠΎ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π° Π‘Π‘Π˜Π‘, я ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠΈΠ» Β«Π² Ρ‚ΠΎΠΏΠ΅Β» запрос для «быстрого» поиска ΠΏΠΎ названию для ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡Π΅ΠΊ ΠΎΡ€Π³Π°Π½ΠΈΠ·Π°Ρ†ΠΈΠΉ.

ΠŸΡ€ΠΈΡ‡Π΅ΠΌ дальнСйшСС расслСдованиС выявило интСрСсный ΠΏΡ€ΠΈΠΌΠ΅Ρ€ сначала ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ, Π° Π·Π°Ρ‚Π΅ΠΌ Π΄Π΅Π³Ρ€Π°Π΄Π°Ρ†ΠΈΠΈ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ запроса ΠΏΡ€ΠΈ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΠΉ Π΅Π³ΠΎ Π΄ΠΎΡ€Π°Π±ΠΎΡ‚ΠΊΠ΅ силами Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… ΠΊΠΎΠΌΠ°Π½Π΄, каТдая ΠΈΠ· ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… дСйствовала ΠΈΡΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΈΠ· Π»ΡƒΡ‡ΡˆΠΈΡ… ΠΏΠΎΠ±ΡƒΠΆΠ΄Π΅Π½ΠΈΠΉ.

0: Ρ‡Π΅Π³ΠΎ ΠΆΠ΅ Ρ…ΠΎΡ‚Π΅Π» ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ

PostgreSQL Antipatterns: сказ ΠΎΠ± ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠΉ Π΄ΠΎΡ€Π°Π±ΠΎΡ‚ΠΊΠ΅ поиска ΠΏΠΎ названию, ΠΈΠ»ΠΈ «ΠžΠΏΡ‚имизация Ρ‚ΡƒΠ΄Π° ΠΈ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ»[ΠšΠ”ΠŸΠ’ ΠΎΡ‚ΡΡŽΠ΄Π°]

Π§Ρ‚ΠΎ Π²ΠΎΠΎΠ±Ρ‰Π΅ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ ΠΏΠΎΠ΄Ρ€Π°Π·ΡƒΠΌΠ΅Π²Π°Π΅Ρ‚ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ, ΠΊΠΎΠ³Π΄Π° Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ ΠΏΡ€ΠΎ «быстрый» поиск ΠΏΠΎ названию? ΠŸΠΎΡ‡Ρ‚ΠΈ Π½ΠΈΠΊΠΎΠ³Π΄Π° это Π½Π΅ оказываСтся «чСстный» поиск ΠΏΠΎ подстрокС Ρ‚ΠΈΠΏΠ° ... LIKE '%Ρ€ΠΎΠ·Π°%' β€” вСдь Ρ‚ΠΎΠ³Π΄Π° Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ ΠΏΠΎΠΏΠ°Π΄Π°ΡŽΡ‚ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ 'Розалия' ΠΈ 'Магазин Π ΠΎΠ·Π°', Π½ΠΎ ΠΈ 'Π“Ρ€ΠΎΠ·Π°' ΠΈ Π΄Π°ΠΆΠ΅ 'Π”ΠΎΠΌ Π”Π΅Π΄Π° ΠœΠΎΡ€ΠΎΠ·Π°'.

ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ ΠΆΠ΅ ΠΏΠΎΠ΄Ρ€Π°Π·ΡƒΠΌΠ΅Π²Π°Π΅Ρ‚ Π½Π° Π±Ρ‹Ρ‚ΠΎΠ²ΠΎΠΌ ΡƒΡ€ΠΎΠ²Π½Π΅, Ρ‡Ρ‚ΠΎ Π²Ρ‹ Π΅ΠΌΡƒ обСспСчитС поиск ΠΏΠΎ Π½Π°Ρ‡Π°Π»Ρƒ слова Π² Π½Π°Π·Π²Π°Π½ΠΈΠΈ ΠΈ ΠΏΠΎΠΊΠ°ΠΆΠ΅Ρ‚Π΅ Π±ΠΎΠ»Π΅Π΅ Ρ€Π΅Π»Π΅Π²Π°Π½Ρ‚Π½Ρ‹ΠΌ Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ начинаСтся Π½Π° Π²Π²Π΅Π΄Π΅Π½Π½ΠΎΠ΅. И сдСлаСтС это практичСски ΠΌΠ³Π½ΠΎΠ²Π΅Π½Π½ΠΎ β€” ΠΏΡ€ΠΈ подстрочном Π²Π²ΠΎΠ΄Π΅.

1: ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΠ²Π°Π΅ΠΌ Π·Π°Π΄Π°Ρ‡Ρƒ

И ΡƒΠΆ Ρ‚Π΅ΠΌ Π±ΠΎΠ»Π΅Π΅ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Ρ‡Π΅Π»ΠΎΠ²Π΅ΠΊ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎ Π²Π²ΠΎΠ΄ΠΈΡ‚ΡŒ 'Ρ€ΠΎΠ· ΠΌΠ°Π³Π°Π·', Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΊΠ°ΠΆΠ΄ΠΎΠ΅ слово Π²Π°ΠΌ ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΠ»ΠΎΡΡŒ ΠΈΡΠΊΠ°Ρ‚ΡŒ прСфиксно. НСт, ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ ΠΎΡ‚Ρ€Π΅Π°Π³ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π½Π° Π±Ρ‹ΡΡ‚Ρ€ΡƒΡŽ подсказку для послСднСго слова Π³ΠΎΡ€Π°Π·Π΄ΠΎ ΠΏΡ€ΠΎΡ‰Π΅, Ρ‡Π΅ΠΌ Ρ†Π΅Π»Π΅Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½Π½ΠΎ Β«Π½Π΅Π΄ΠΎΠ²Π²ΠΎΠ΄ΠΈΡ‚ΡŒΒ» ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠ΅ β€” посмотритС, ΠΊΠ°ΠΊ это ΠΎΡ‚Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ любой поисковик.

Π’ΠΎΠΎΠ±Ρ‰Π΅, ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ ΡΡ„ΠΎΡ€ΠΌΡƒΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ трСбования ΠΊ Π·Π°Π΄Π°Ρ‡Π΅ β€” большС ΠΏΠΎΠ»ΠΎΠ²ΠΈΠ½Ρ‹ Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ. Иногда Π²Π½ΠΈΠΌΠ°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ Π°Π½Π°Π»ΠΈΠ· use case ΠΌΠΎΠΆΠ΅Ρ‚ сущСствСнно Π²Π»ΠΈΡΡ‚ΡŒ Π½Π° Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚.

Π§Ρ‚ΠΎ ΠΆΠ΅ Π΄Π΅Π»Π°Π΅Ρ‚ абстрактный Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ?

1.0: внСшний поисковый Π΄Π²ΠΈΠΆΠΎΠΊ

Ой, поиск это слоТно, Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π²ΠΎΠΎΠ±Ρ‰Π΅ ΠΈΠΌ Π·Π°Π½ΠΈΠΌΠ°Ρ‚ΡŒΡΡ Π½Π΅ хочСтся β€” Π΄Π°Π²Π°ΠΉΡ‚Π΅ ΠΎΡ‚Π΄Π°Π΄ΠΈΠΌ это devops! ΠŸΡƒΡΡ‚ΡŒ ΠΎΠ½ΠΈ Π½Π°ΠΌ Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ внСшнюю ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Π‘Π” ΠΏΠΎΠΈΡΠΊΠΎΠ²ΡƒΡŽ систСму: Sphinx, ElasticSearch,…

Π Π°Π±ΠΎΡ‡ΠΈΠΉ, Ρ…ΠΎΡ‚ΡŒ ΠΈ Ρ‚Ρ€ΡƒΠ΄ΠΎΠ΅ΠΌΠΊΠΈΠΉ Π² ΠΏΠ»Π°Π½Π΅ синхронизации ΠΈ опСративности ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚. Но Π½Π΅ Π² нашСм случаС, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ поиск осущСствляСтся для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² Ρ€Π°ΠΌΠΊΠ°Ρ… Π΄Π°Π½Π½Ρ‹Ρ… Π΅Π³ΠΎ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°. А Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠΌΠ΅ΡŽΡ‚ достаточно Π²Ρ‹ΡΠΎΠΊΡƒΡŽ ΠΈΠ·ΠΌΠ΅Π½Ρ‡ΠΈΠ²ΠΎΡΡ‚ΡŒ β€” ΠΈ Ссли сСйчас ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€ внСс ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΡƒ 'Магазин Π ΠΎΠ·Π°', Ρ‚ΠΎ Ρ‡Π΅Ρ€Π΅Π· 5-10 сСкунд ΠΎΠ½ ΡƒΠΆΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π²ΡΠΏΠΎΠΌΠ½ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ Π·Π°Π±Ρ‹Π» ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ Ρ‚Π°ΠΌ email ΠΈ Π·Π°Ρ…ΠΎΡ‚Π΅Ρ‚ΡŒ Π΅Π΅ Π½Π°ΠΉΡ‚ΠΈ ΠΈ ΠΏΠΎΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ.

ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ β€” Π΄Π°Π²Π°ΠΉΡ‚Π΅ ΠΈΡΠΊΠ°Ρ‚ΡŒ «прямо ΠΏΠΎ Π±Π°Π·Π΅Β». К ΡΡ‡Π°ΡΡ‚ΡŒΡŽ, PostgreSQL позволяСт Π½Π°ΠΌ это Π΄Π΅Π»Π°Ρ‚ΡŒ, ΠΈ Π½Π΅ ΠΎΠ΄Π½ΠΈΠΌ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ΠΎΠΌ β€” ΠΈΡ… ΠΈ рассмотрим.

1.1: «чСстная» подстрока

ЦСпляСмся Π·Π° слово «подстрока». А вСдь Ρ€ΠΎΠ²Π½ΠΎ для индСксного поиска ΠΏΠΎ подстрокС (ΠΈ Π΄Π°ΠΆΠ΅ ΠΏΠΎ рСгулярным выраТСниям!) Π΅ΡΡ‚ΡŒ ΠΎΡ‚Π»ΠΈΡ‡Π½Ρ‹ΠΉ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ pg_trgm! Волько ΠΏΠΎΡ‚ΠΎΠΌ Π½Π°Π΄ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ ΠΏΠΎΡΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ.

Π”Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π²Π·ΡΡ‚ΡŒ для простоты ΠΌΠΎΠ΄Π΅Π»ΠΈ Ρ‚Π°ΠΊΡƒΡŽ Ρ‚Π°Π±Π»ΠΈΡ‡ΠΊΡƒ:

CREATE TABLE firms(
  id
    serial
      PRIMARY KEY
, name
    text
);

Π—Π°Π»ΠΈΠ²Π°Π΅ΠΌ Ρ‚ΡƒΠ΄Π° 7.8 ΠΌΠΈΠ»Π»ΠΈΠΎΠ½ΠΎΠ² записСй Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Ρ… ΠΎΡ€Π³Π°Π½ΠΈΠ·Π°Ρ†ΠΈΠΉ ΠΈ индСксируСм:

CREATE EXTENSION pg_trgm;
CREATE INDEX ON firms USING gin(lower(name) gin_trgm_ops);

ΠŸΠΎΠΈΡ‰Π΅ΠΌ для подстрочного поиска ΠΏΠ΅Ρ€Π²Ρ‹Π΅ 10 записСй:

SELECT
  *
FROM
  firms
WHERE
  lower(name) ~ ('(^|s)' || 'Ρ€ΠΎΠ·Π°')
ORDER BY
  lower(name) ~ ('^' || 'Ρ€ΠΎΠ·Π°') DESC -- сначала "Π½Π°Ρ‡ΠΈΠ½Π°ΡŽΡ‰ΠΈΠ΅ΡΡ Π½Π°"
, lower(name) -- ΠΎΡΡ‚Π°Π»ΡŒΠ½ΠΎΠ΅ ΠΏΠΎ Π°Π»Ρ„Π°Π²ΠΈΡ‚Ρƒ
LIMIT 10;

PostgreSQL Antipatterns: сказ ΠΎΠ± ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠΉ Π΄ΠΎΡ€Π°Π±ΠΎΡ‚ΠΊΠ΅ поиска ΠΏΠΎ названию, ΠΈΠ»ΠΈ «ΠžΠΏΡ‚имизация Ρ‚ΡƒΠ΄Π° ΠΈ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ»
[ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° explain.tensor.ru]

Ну, такоС… 26мс, 31MB ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ большС 1.7K ΠΎΡ‚Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ²Π°Π½Π½Ρ‹Ρ… записСй β€” для 10 искомых. НакладныС расходы слишком Π²Π΅Π»ΠΈΠΊΠΈ, нСльзя Π»ΠΈ ΠΊΠ°ΠΊ-Ρ‚ΠΎ поэффСктивнСС?

1.2: поиск ΠΏΠΎ тСксту? это ΠΆΠ΅ FTS!

Π”Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ, PostgreSQL прСдоставляСт ΠΎΡ‡Π΅Π½ΡŒ ΠΌΠΎΡ‰Π½Ρ‹ΠΉ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ полнотСкстового поиска (Full Text Search), Π² Ρ‚ΠΎΠΌ числС с Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒΡŽ прСфиксного поиска. ΠžΡ‚Π»ΠΈΡ‡Π½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚, Π΄Π°ΠΆΠ΅ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠΉ ΡƒΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Ρ‚ΡŒ Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ! Π”Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ:

CREATE INDEX ON firms USING gin(to_tsvector('simple'::regconfig, lower(name)));

SELECT
  *
FROM
  firms
WHERE
  to_tsvector('simple'::regconfig, lower(name)) @@ to_tsquery('simple', 'Ρ€ΠΎΠ·Π°:*')
ORDER BY
  lower(name) ~ ('^' || 'Ρ€ΠΎΠ·Π°') DESC
, lower(name)
LIMIT 10;

PostgreSQL Antipatterns: сказ ΠΎΠ± ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠΉ Π΄ΠΎΡ€Π°Π±ΠΎΡ‚ΠΊΠ΅ поиска ΠΏΠΎ названию, ΠΈΠ»ΠΈ «ΠžΠΏΡ‚имизация Ρ‚ΡƒΠ΄Π° ΠΈ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ»
[ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° explain.tensor.ru]

Π’ΡƒΡ‚ Π½Π°ΠΌ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠΌΠΎΠ³Π»Π° параллСлизация исполнСния запроса, сократив врСмя Π²Π΄Π²ΠΎΠ΅ Π΄ΠΎ 11мс. Π”Π° ΠΈ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ Π½Π°ΠΌ ΠΏΡ€ΠΈΡˆΠ»ΠΎΡΡŒ Π² 1.5 Ρ€Π°Π·Π° мСньшС β€” всСго 20MB. А Ρ‚ΡƒΡ‚ Ρ‡Π΅ΠΌ мСньшС β€” Ρ‚Π΅ΠΌ Π»ΡƒΡ‡ΡˆΠ΅, вСдь Ρ‡Π΅ΠΌ больший объСм ΠΌΡ‹ Π²Ρ‹Ρ‡ΠΈΡ‚Ρ‹Π²Π°Π΅ΠΌ, Ρ‚Π΅ΠΌ Π²Ρ‹ΡˆΠ΅ ΡˆΠ°Π½ΡΡ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ cache miss, ΠΈ каТдая лишняя прочитанная с диска страница Π΄Π°Π½Π½Ρ‹Ρ… β€” ΠΏΠΎΡ‚Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Π΅ Β«Ρ‚ΠΎΡ€ΠΌΠΎΠ·Π°Β» для запроса.

1.3: всС-Ρ‚Π°ΠΊΠΈ LIKE?

ВсСм ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΉ запрос Ρ…ΠΎΡ€ΠΎΡˆ, Π΄Π° Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ссли Π΅Π³ΠΎ Π΄Π΅Ρ€Π½ΡƒΡ‚ΡŒ ΡΠΎΡ‚Π½ΡŽ тысяч Ρ€Π°Π· Π·Π° сутки, Ρ‚ΠΎ Π½Π°Π±Π΅ΠΆΠΈΡ‚ ΡƒΠΆΠ΅ 2TB ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ…. Π’ Π»ΡƒΡ‡ΡˆΠ΅ΠΌ случаС β€” ΠΈΠ· памяти, Π½ΠΎ Ссли Π½Π΅ ΠΏΠΎΠ²Π΅Π·Π΅Ρ‚, Ρ‚ΠΎ ΠΈ с диска. Π’Π°ΠΊ Ρ‡Ρ‚ΠΎ Π΄Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π΅Π³ΠΎ помСньшС.

Вспомним, Ρ‡Ρ‚ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Ρ…ΠΎΡ‡Π΅Ρ‚ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ сначала Β«ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½Π°Ρ‡ΠΈΠ½Π°ΡŽΡ‚ΡΡ Π½Π° …Β». Π’Π°ΠΊ вСдь это ΠΆΠ΅ Π² чистом Π²ΠΈΠ΄Π΅ прСфиксный поиск с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ text_pattern_ops! И Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ссли Π½Π°ΠΌ Β«Π½Π΅ Ρ…Π²Π°Ρ‚ΠΈΡ‚Β» Π΄ΠΎ 10 искомых записСй, Ρ‚ΠΎ Π΄ΠΎΡ‡ΠΈΡ‚Ρ‹Π²Π°Ρ‚ΡŒ ΠΈΡ… придСтся с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ FTS-поиска:

CREATE INDEX ON firms(lower(name) text_pattern_ops);

SELECT
  *
FROM
  firms
WHERE
  lower(name) LIKE ('Ρ€ΠΎΠ·Π°' || '%')
LIMIT 10;

PostgreSQL Antipatterns: сказ ΠΎΠ± ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠΉ Π΄ΠΎΡ€Π°Π±ΠΎΡ‚ΠΊΠ΅ поиска ΠΏΠΎ названию, ΠΈΠ»ΠΈ «ΠžΠΏΡ‚имизация Ρ‚ΡƒΠ΄Π° ΠΈ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ»
[ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° explain.tensor.ru]

ΠžΡ‚Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ β€” всСго 0.05мс ΠΈ Ρ‡ΡƒΡ‚ΡŒ большС 100KB ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½ΠΎ! Волько ΠΌΡ‹ ΠΆΠ΅ Π·Π°Π±Ρ‹Π»ΠΈ сортировку ΠΏΠΎ названию, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π½Π΅ заблудился Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°Ρ…:

SELECT
  *
FROM
  firms
WHERE
  lower(name) LIKE ('Ρ€ΠΎΠ·Π°' || '%')
ORDER BY
  lower(name)
LIMIT 10;

PostgreSQL Antipatterns: сказ ΠΎΠ± ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠΉ Π΄ΠΎΡ€Π°Π±ΠΎΡ‚ΠΊΠ΅ поиска ΠΏΠΎ названию, ΠΈΠ»ΠΈ «ΠžΠΏΡ‚имизация Ρ‚ΡƒΠ΄Π° ΠΈ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ»
[ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° explain.tensor.ru]

Ой, Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ ΡƒΠΆΠ΅ Π½Π΅ Ρ‚Π°ΠΊ красиво β€” Π²Ρ€ΠΎΠ΄Π΅ ΠΈ индСкс Π΅ΡΡ‚ΡŒ, Π½ΠΎ сортировка Π»Π΅Ρ‚ΠΈΡ‚ ΠΌΠΈΠΌΠΎ нСго… Оно, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, ΡƒΠΆΠ΅ Π² Ρ€Π°Π·Ρ‹ эффСктивнСС, Ρ‡Π΅ΠΌ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚, но…

1.4: Β«Π΄ΠΎΡ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ напильником»

Но Π΅ΡΡ‚ΡŒ ΠΆΠ΅ индСкс, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ позволяСт ΠΈ ΠΏΠΎ Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½Ρƒ ΠΈΡΠΊΠ°Ρ‚ΡŒ, ΠΈ сортировку ΠΏΡ€ΠΈ этом Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ β€” ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ btree!

CREATE INDEX ON firms(lower(name));

Волько запрос ΠΏΠΎΠ΄ Π½Π΅Π³ΠΎ придСтся Β«ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽΒ»:

SELECT
  *
FROM
  firms
WHERE
  lower(name) >= 'Ρ€ΠΎΠ·Π°' AND
  lower(name) <= ('Ρ€ΠΎΠ·Π°' || chr(65535)) -- для UTF8, для ΠΎΠ΄Π½ΠΎΠ±Π°ΠΉΡ‚ΠΎΠ²Ρ‹Ρ… - chr(255)
ORDER BY
   lower(name)
LIMIT 10;

PostgreSQL Antipatterns: сказ ΠΎΠ± ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠΉ Π΄ΠΎΡ€Π°Π±ΠΎΡ‚ΠΊΠ΅ поиска ΠΏΠΎ названию, ΠΈΠ»ΠΈ «ΠžΠΏΡ‚имизация Ρ‚ΡƒΠ΄Π° ΠΈ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ»
[ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° explain.tensor.ru]

ΠžΡ‚Π»ΠΈΡ‡Π½ΠΎ β€” ΠΈ сортировка Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚, ΠΈ ΠΏΠΎΡ‚Ρ€Π΅Π±Π»Π΅Π½ΠΈΠ΅ рСсурсов ΠΎΡΡ‚Π°Π»ΠΎΡΡŒ «микроскопичСским», Π² тысячи Ρ€Π°Π· эффСктивнСС «чистого» FTS! ΠžΡΡ‚Π°Π»ΠΎΡΡŒ ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ Π² Π΅Π΄ΠΈΠ½Ρ‹ΠΉ запрос:

(
  SELECT
    *
  FROM
    firms
  WHERE
    lower(name) >= 'Ρ€ΠΎΠ·Π°' AND
    lower(name) <= ('Ρ€ΠΎΠ·Π°' || chr(65535)) -- для UTF8, для ΠΎΠ΄Π½ΠΎΠ±Π°ΠΉΡ‚ΠΎΠ²Ρ‹Ρ… ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΎΠΊ - chr(255)
  ORDER BY
     lower(name)
  LIMIT 10
)
UNION ALL
(
  SELECT
    *
  FROM
    firms
  WHERE
    to_tsvector('simple'::regconfig, lower(name)) @@ to_tsquery('simple', 'Ρ€ΠΎΠ·Π°:*') AND
    lower(name) NOT LIKE ('Ρ€ΠΎΠ·Π°' || '%') -- "Π½Π°Ρ‡ΠΈΠ½Π°ΡŽΡ‰ΠΈΠ΅ΡΡ Π½Π°" ΠΌΡ‹ ΡƒΠΆΠ΅ нашли Π²Ρ‹ΡˆΠ΅
  ORDER BY
    lower(name) ~ ('^' || 'Ρ€ΠΎΠ·Π°') DESC -- ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Ρ‚Ρƒ ΠΆΠ΅ сортировку, Ρ‡Ρ‚ΠΎΠ±Ρ‹ НЕ ΠΏΠΎΠΉΡ‚ΠΈ ΠΏΠΎ btree-индСксу
  , lower(name)
  LIMIT 10
)
LIMIT 10;

Π—Π°ΠΌΠ΅Ρ‡Ρƒ, Ρ‡Ρ‚ΠΎ Π²Ρ‚ΠΎΡ€ΠΎΠΉ подзапрос выполняСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ссли ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ Π²Π΅Ρ€Π½ΡƒΠ» мСньшС ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌΠΎΠ³ΠΎ послСдним LIMIT количСства строк. ΠŸΡ€ΠΎ Ρ‚Π°ΠΊΠΎΠΉ способ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ запросов я ΡƒΠΆΠ΅ писал Ρ€Π°Π½ΡŒΡˆΠ΅.

Π’Π°ΠΊΠΈ Π΄Π°, ΠΌΡ‹ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΈΠΌΠ΅Π΅ΠΌ Π½Π° Ρ‚Π°Π±Π»ΠΈΡ†Π΅ ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ btree ΠΈ gin, Π·Π°Ρ‚ΠΎ статистичСски ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ, Ρ‡Ρ‚ΠΎ мСньшС 10% запросов доходят Π΄ΠΎ выполнСния Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ Π±Π»ΠΎΠΊΠ°. Π’ΠΎ Π΅ΡΡ‚ΡŒ ΠΏΡ€ΠΈ Ρ‚Π°ΠΊΠΈΡ… извСстных Π·Π°Ρ€Π°Π½Π΅Π΅ Ρ‚ΠΈΠΏΠΈΡ‡Π½Ρ‹Ρ… ограничСниях для Π·Π°Π΄Π°Ρ‡ΠΈ ΠΌΡ‹ смогли ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΡ‚ΡŒ суммарноС ΠΏΠΎΡ‚Ρ€Π΅Π±Π»Π΅Π½ΠΈΠ΅ рСсурсов сСрвСра практичСски Π² тысячи Ρ€Π°Π·!

1.5*: обойдСмся бСз напильника

Π’Ρ‹ΡˆΠ΅ LIKE Π½Π°ΠΌ помСшала ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π½Π΅ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Π°Ρ сортировка. Но Π΅Π΅ ΠΌΠΎΠΆΠ½ΠΎ Β«Π½Π°ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Π½Π° ΠΏΡƒΡ‚ΡŒ истинный» с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ указания USING-ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π°:

По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ подразумСваСтся ASC. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, ΠΌΠΎΠΆΠ½ΠΎ Π·Π°Π΄Π°Ρ‚ΡŒ имя спСцифичСского ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π° сортировки Π² ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠΈ USING. ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ сортировки Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ Ρ‡Π»Π΅Π½ΠΎΠΌ «мСньшС» ΠΈΠ»ΠΈ «большС» Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ сСмСйства ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠ² B-Π΄Π΅Ρ€Π΅Π²Π°. ASC ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ Ρ€Π°Π²Π½ΠΎΠ·Π½Π°Ρ‡Π½ΠΎ USING < ΠΈ DESC ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ Ρ€Π°Π²Π½ΠΎΠ·Π½Π°Ρ‡Π½ΠΎ USING >.

Π’ нашСм случаС «мСньшС» β€” это ~<~:

SELECT
  *
FROM
  firms
WHERE
  lower(name) LIKE ('Ρ€ΠΎΠ·Π°' || '%')
ORDER BY
  lower(name) USING ~<~
LIMIT 10;

PostgreSQL Antipatterns: сказ ΠΎΠ± ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠΉ Π΄ΠΎΡ€Π°Π±ΠΎΡ‚ΠΊΠ΅ поиска ΠΏΠΎ названию, ΠΈΠ»ΠΈ «ΠžΠΏΡ‚имизация Ρ‚ΡƒΠ΄Π° ΠΈ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ»
[ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° explain.tensor.ru]

2: ΠΊΠ°ΠΊ Β«ΠΏΡ€ΠΎΠΊΠΈΡΠ°ΡŽΡ‚Β» запросы

Π’Π΅ΠΏΠ΅Ρ€ΡŒ оставляСм наш запрос Β«Π½Π°ΡΡ‚ΠΎΡΡ‚ΡŒΡΡΒ» ΠΏΠΎΠ»Π³ΠΎΠ΄Π°-Π³ΠΎΠ΄, ΠΈ с ΡƒΠ΄ΠΈΠ²Π»Π΅Π½ΠΈΠ΅ΠΌ снова ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠΈΠ²Π°Π΅ΠΌ Π΅Π³ΠΎ Β«Π² Ρ‚ΠΎΠΏΠ΅Β» с показатСлями суммарного суточного «прокачивания» памяти (buffers shared hit) Π² 5.5TB β€” Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ Π΅Ρ‰Π΅ большС, Ρ‡Π΅ΠΌ Π±Ρ‹Π»ΠΎ исходно.

НСт, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, ΠΈ бизнСс Ρƒ нас вырос, ΠΈ Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠ° ΡƒΠ²Π΅Π»ΠΈΡ‡ΠΈΠ»Π°ΡΡŒ, Π½ΠΎ Π½Π΅ Π½Π°ΡΡ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΆΠ΅! Π—Π½Π°Ρ‡ΠΈΡ‚, Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Ρ‚ΡƒΡ‚ нСчисто β€” Π΄Π°Π²Π°ΠΉΡ‚Π΅ Ρ€Π°Π·Π±ΠΈΡ€Π°Ρ‚ΡŒΡΡ.

2.1: Ρ€ΠΎΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΏΠ΅ΠΉΠ΄ΠΆΠΈΠ½Π³Π°

Π’ ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π΄Ρ€ΡƒΠ³ΠΎΠΉ ΠΊΠΎΠΌΠ°Π½Π΄Π΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ² Π·Π°Ρ…ΠΎΡ‚Π΅Π»ΠΎΡΡŒ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΠΈΠ· быстрого подстрочного поиска Β«ΠΏΡ€Ρ‹Π³Π½ΡƒΡ‚ΡŒΒ» Π² рССстр с Ρ‚Π΅ΠΌΠΈ ΠΆΠ΅, Π½ΠΎ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½Π½Ρ‹ΠΌΠΈ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°ΠΌΠΈ. А ΠΊΠ°ΠΊΠΎΠΉ рССстр Π±Π΅Π· постраничной Π½Π°Π²ΠΈΠ³Π°Ρ†ΠΈΠΈ? Π”Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΡ€ΠΈΠΊΡ€ΡƒΡ‚ΠΈΠΌ!

( ... LIMIT <N> + 10)
UNION ALL
( ... LIMIT <N> + 10)
LIMIT 10 OFFSET <N>;

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΠΎΠΆΠ½ΠΎ Π±Ρ‹Π»ΠΎ Π±Π΅Π· напрягов для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ° ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ рССстр Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² поиска с Β«Ρ‚ΠΈΠΏΠ°-постраничной» ΠΏΠΎΠ΄Π³Ρ€ΡƒΠ·ΠΊΠΎΠΉ.

ΠšΠΎΠ½Π΅Ρ‡Π½ΠΎ, Π½Π° самом-Ρ‚ΠΎ Π΄Π΅Π»Π΅, для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ страницы Π΄Π°Π½Π½Ρ‹Ρ… читаСтся всС большС ΠΈ большС (всС ΠΈΠ· ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π³ΠΎ Ρ€Π°Π·Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ отбросим, плюс Π½ΡƒΠΆΠ½Ρ‹ΠΉ «хвостик») β€” Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ это ΠΎΠ΄Π½ΠΎΠ·Π½Π°Ρ‡Π½Ρ‹ΠΉ Π°Π½Ρ‚ΠΈΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½. А ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Π΅Π΅ Π±Ρ‹Π»ΠΎ Π±Ρ‹ β€” Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ поиск Π½Π° ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ ΠΈΡ‚Π΅Ρ€Π°Ρ†ΠΈΠΈ ΠΎΡ‚ Π·Π°ΠΏΠΎΠΌΠ½Π΅Π½Π½ΠΎΠ³ΠΎ Π² интСрфСйсС ΠΊΠ»ΡŽΡ‡Π°, Π½ΠΎ ΠΏΡ€ΠΎ это β€” Π² Π΄Ρ€ΡƒΠ³ΠΎΠΉ Ρ€Π°Π·.

2.2: хочСтся экзотики

Π’ ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΡƒ Π·Π°Ρ…ΠΎΡ‚Π΅Π»ΠΎΡΡŒ Ρ€Π°Π·Π½ΠΎΠΎΠ±Ρ€Π°Π·ΠΈΡ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚ΠΈΡ€ΡƒΡŽΡ‰ΡƒΡŽ Π²Ρ‹Π±ΠΎΡ€ΠΊΡƒ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ ΠΈΠ· Π΄Ρ€ΡƒΠ³ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹, для Ρ‡Π΅Π³ΠΎ вСсь ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΉ запрос Π±Ρ‹Π» ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ Π² CTE:

WITH q AS (
  ...
  LIMIT <N> + 10
)
SELECT
  *
, (SELECT ...) sub_query -- ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ запрос ΠΊ связанной Ρ‚Π°Π±Π»ΠΈΡ†Π΅
FROM
  q
LIMIT 10 OFFSET <N>;

И Π΄Π°ΠΆΠ΅ Ρ‚Π°ΠΊ β€” Π½Π΅ΠΏΠ»ΠΎΡ…ΠΎ, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹ΠΉ запрос вычисляСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для 10 Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΡ‹Ρ… записСй, Ссли Π±Ρ‹ нС…

2.3: DISTINCT бСссмыслСнный ΠΈ бСспощадный

Π“Π΄Π΅-Ρ‚ΠΎ Π² процСссС Ρ‚Π°ΠΊΠΎΠΉ ΡΠ²ΠΎΠ»ΡŽΡ†ΠΈΠΈ ΠΈΠ· 2-Π³ΠΎ подзапроса ΠΏΠΎΡ‚Π΅Ρ€ΡΠ»ΠΎΡΡŒ NOT LIKE условиС. ΠŸΠΎΠ½ΡΡ‚Π½ΠΎ, Ρ‡Ρ‚ΠΎ послС этого UNION ALL Π½Π°Ρ‡Π°Π» Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ записи Π΄Π²Π°ΠΆΠ΄Ρ‹ β€” сначала Π½Π°ΠΉΠ΄Π΅Π½Π½Ρ‹Π΅ ΠΏΠΎ Π½Π°Ρ‡Π°Π»Ρƒ строки, Π° ΠΏΠΎΡ‚ΠΎΠΌ Π΅Ρ‰Π΅ Ρ€Π°Π· β€” ΠΏΠΎ Π½Π°Ρ‡Π°Π»Ρƒ ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ слова этой строки. Π’ ΠΏΡ€Π΅Π΄Π΅Π»Π΅, всС записи 2Π³ΠΎ подзапроса ΠΌΠΎΠ³Π»ΠΈ ΡΠΎΠ²ΠΏΠ°ΡΡ‚ΡŒ с записями ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ.

Π§Ρ‚ΠΎ Π΄Π΅Π»Π°Π΅Ρ‚ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ вмСсто поиска ΠΏΡ€ΠΈΡ‡ΠΈΠ½Ρ‹?.. НС вопрос!

  • Ρ€Π°ΡΡˆΠΈΡ€ΠΈΠΌ Π²Π΄Π²ΠΎΠ΅ Ρ€Π°Π·ΠΌΠ΅Ρ€ исходных Π²Ρ‹Π±ΠΎΡ€ΠΎΠΊ
  • Π½Π°Π»ΠΎΠΆΠΈΠΌ DISTINCT, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈΡΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄ΠΈΠ½Π°Ρ€Π½Ρ‹Π΅ экзСмпляры ΠΊΠ°ΠΆΠ΄ΠΎΠΉ строки

WITH q AS (
  ( ... LIMIT <2 * N> + 10)
  UNION ALL
  ( ... LIMIT <2 * N> + 10)
  LIMIT <2 * N> + 10
)
SELECT DISTINCT
  *
, (SELECT ...) sub_query
FROM
  q
LIMIT 10 OFFSET <N>;

Π’ΠΎ Π΅ΡΡ‚ΡŒ понятно, Ρ‡Ρ‚ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚, Π² ΠΈΡ‚ΠΎΠ³Π΅, Ρ€ΠΎΠ²Π½ΠΎ Ρ‚ΠΎΡ‚ ΠΆΠ΅, Π½ΠΎ шанс Β«ΠΏΡ€ΠΎΠ»Π΅Ρ‚Π΅Ρ‚ΡŒΒ» Π²ΠΎ 2-ΠΉ подзапрос CTE стал сильно Π²Ρ‹ΡˆΠ΅, Π΄Π° ΠΈ Π±Π΅Π· этого, читаСтся явно большС.

Но это Π½Π΅ самая ΠΏΠ΅Ρ‡Π°Π»ΡŒ. ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ попросил ΠΎΡ‚ΠΎΠ±Ρ€Π°Ρ‚ΡŒ DISTINCT Π½Π΅ ΠΏΠΎ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹ΠΌ, Π° сразу ΠΏΠΎ всСм полям записи, Ρ‚ΠΎ Ρ‚ΡƒΠ΄Π° Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΎΠΌ ΠΏΠΎΠΏΠ°Π»ΠΎ ΠΈ ΠΏΠΎΠ»Π΅ sub_query β€” Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ подзапроса. Π’Π΅ΠΏΠ΅Ρ€ΡŒ, для выполнСния DISTINCT, Π±Π°Π·Π΅ ΠΏΡ€ΠΈΡˆΠ»ΠΎΡΡŒ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΡƒΠΆΠ΅ Π½Π΅ 10 подзапросов, Π° всС <2 * N> + 10!

2.4: коопСрация ΠΏΡ€Π΅Π²Ρ‹ΡˆΠ΅ всСго!

Π’ΠΎΡ‚ Ρ‚Π°ΠΊ Π²ΠΎΡ‚, Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ ΠΆΠΈΠ»ΠΈ β€” Π½Π΅ Ρ‚ΡƒΠΆΠΈΠ»ΠΈ, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Π² рССстрС Β«Π΄ΠΎΠΊΡ€ΡƒΡ‚ΠΈΡ‚ΡŒΒ» Π΄ΠΎ сущСствСнных Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ N ΠΏΡ€ΠΈ хроничСском Π·Π°ΠΌΠ΅Π΄Π»Π΅Π½ΠΈΠΈ получСния ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ «страницы» Ρƒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ явно Π½Π΅ Ρ…Π²Π°Ρ‚Π°Π»ΠΎ тСрпСния.

Пока ΠΊ Π½ΠΈΠΌ Π½Π΅ ΠΏΡ€ΠΈΡˆΠ»ΠΈ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ ΠΈΠ· Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ ΠΎΡ‚Π΄Π΅Π»Π°, ΠΈ Π½Π΅ Π·Π°Ρ…ΠΎΡ‚Π΅Π»ΠΈ Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ Ρ‚Π°ΠΊΠΈΠΌ ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΌ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠΌ для ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠ³ΠΎ поиска β€” Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ Π±Π΅Ρ€Π΅ΠΌ ΠΈΠ· ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ Π²Ρ‹Π±ΠΎΡ€ΠΊΠΈ кусочСк, Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΡƒΠ΅ΠΌ ΠΏΠΎ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ условиям, рисуСм Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚, ΠΏΠΎΡ‚ΠΎΠΌ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ кусочСк (Ρ‡Ρ‚ΠΎ Π² нашСм случаС достигаСтся Π·Π° счСт увСличСния N), ΠΈ Ρ‚Π°ΠΊ ΠΏΠΎΠΊΠ° Π½Π΅ Π·Π°ΠΏΠΎΠ»Π½ΠΈΠΌ экран.

Π’ ΠΎΠ±Ρ‰Π΅ΠΌ, Π² ΠΏΠΎΠΉΠΌΠ°Π½Π½ΠΎΠΌ экзСмплярС N достигло Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ ΠΏΠΎΡ‡Ρ‚ΠΈ Π² 17K, Π° всСго Π·Π° сутки Π±Ρ‹Π»ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ Β«ΠΏΠΎ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ΅Β» Π½Π΅ мСньшС 4K Ρ‚Π°ΠΊΠΈΡ… запросов. ПослСдниС ΠΈΠ· Π½ΠΈΡ… смСло сканировали ΡƒΠΆΠ΅ ΠΏΠΎ 1GB памяти Π½Π° ΠΊΠ°ΠΆΠ΄ΠΎΠΉ итСрации…

Π˜Ρ‚ΠΎΠ³ΠΎ

PostgreSQL Antipatterns: сказ ΠΎΠ± ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠΉ Π΄ΠΎΡ€Π°Π±ΠΎΡ‚ΠΊΠ΅ поиска ΠΏΠΎ названию, ΠΈΠ»ΠΈ «ΠžΠΏΡ‚имизация Ρ‚ΡƒΠ΄Π° ΠΈ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ»

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com