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

По-стабилни съпоставяния с поддръжка на ICU в PostgreSQL 10

В тази статия искам да представя поддръжката на ICU в PostgreSQL, върху която работих за PostgreSQL версия 10, за да се появи по-късно тази година.

Сортиране

Сортирането е важна функционалност на системата от база данни. Първо, потребителите обикновено искат да видят сортирани данни. Всеки резултат от заявка, който съдържа повече от един ред и е предназначен за консумация от крайни потребители, вероятно ще иска да бъде сортиран, само за по-добро потребителско изживяване. Второ, голяма част от вътрешната функционалност на системата за бази данни зависи от сортирането на данни или наличието на сортирани данни. Индексите на B-дървото са очевиден пример. Индексите BRIN имат познания за реда. Разделянето на диапазона трябва да сравнява стойностите. Обединяванията за сливане зависят от сортирания вход. Идеята, която е обща за тези различни техники, е, че грубо казано, ако сте сортирали данни и знаете какво търсите, това прави много по-бързо намирането на мястото, където трябва да бъде намерено.

Има два важни аспекта на сортирането. Единият е алгоритъмът за сортиране. Това е стандартна тема в компютърните науки и много работа е вложена в PostgreSQL през годините за прецизиране на различните алгоритми и методи за сортиране, но не за това ще пиша. Другият решава в какъв ред трябва да бъдат нещата, което наричаме съпоставяне. В много случаи този избор е очевиден. 1 идва преди 2. FALSE идва преди TRUE ... е, някой просто произволно е решил това. A обикновено идва преди B. Но когато става въпрос за текст на естествен език, нещата стават интересни. Има много различни начини за подреждане на текст и действителните методи за съпоставяне на текстови низове са по-сложни, отколкото може да изглежда. Различните езици предпочитат различни редове на сортиране, но дори в рамките на един език може да има вариации за различните приложения. Има и подробности, за които да се притеснявате, като например какво да правите с интервалите, пунктуацията, разликите в малките букви, диакритичните знаци и т.н. Потърсете алгоритъма за съпоставяне на Unicode за повече представа за това.

Преди функцията ICU да бъде ангажирана, цялата тази функционалност, улеснена от библиотеката C в операционната система. PostgreSQL по принцип просто предава низове на strcmp() , strcoll() , и други подобни и работи с резултата. Библиотеките C в различните операционни системи прилагат различните варианти и нюанси, споменати по-горе, на различни нива на функционалност и качество, така че PostgreSQL може да прави това, което вашата операционна система може да прави.

Промяна на съпоставянията

Проблемите започват, ако операционната система някога трябва да промени съпоставянето, което предоставя. Защо биха искали да направят това? Възможно е предишното съпоставяне да е било погрешно и да е трябвало да бъде коригирано. Може би е публикуван нов стандарт за език и съпоставянето трябва да бъде актуализирано за това. Може би вътрешното представяне на данните за съпоставяне и низове е променено поради причини за производителност или защото е било необходимо да се внедри допълнителна функционалност. За много програми това не е проблем. Може просто да видите малко по-различно подреден изход, ако изобщо забележите разлика. За система от база данни обаче това е сериозен проблем. Както е описано по-горе, PostgreSQL съхранява сортирани данни в индекси и други места и разчита на реда на сортиране да бъде правилен. Ако редът на сортиране не е правилен, търсенето в индекс може да не намери данни, които всъщност са там. Или запис в индекс ще запише на друго място. Или данните се записват или четат от грешен дял. Това може да доведе до погрешно дублиране на данни или до появата на загуба на данни, тъй като данните не са там, където се търсят. С други думи, това може да доведе до повреда на данните и (очевидна) загуба на данни.

За съжаление досега не можехме да направим много по въпроса. Операционните системи актуализират своите съпоставяния, когато пожелаят, може би като част от надграждане на техния пакет C библиотека. Няма начин да разберете за това по разумен начин или може би като проверите подробно пакетите за актуализация. И дори тогава, ще отхвърлите ли важна актуализация на вашата C библиотека, защото сте забелязали, че съпоставянето в някой локал, който не използвате, е променен? Беше много неудобна ситуация.

Влезте в ICU

И така, къде идва интензивното отделение? ICU, международни компоненти за Unicode, е библиотека, която предоставя средства за интернационализация и локализация, включително съпоставяне. Така че в това отношение това е алтернатива на използването на средствата в стандартната C библиотека. Хубавото е, че ICU изрично предоставя някои гаранции за стабилността на съпоставянията:

  • Съпоставянето няма да бъде променено по несъвместим начин като част от незначителна актуализация на изданието.
  • Споставянето има версия, която може да бъде проверена и когато съпоставянето се промени по несъвместим начин, версията се променя.

За потребителите на PostgreSQL това на практика ще означава:

  • Рутинните актуализации на пакети на операционната система няма да попречат на валидността на сортираните данни. Тъй като postgres binary е свързан с определена основна версия на libicu , рутинните надстройки на пакети на операционната система няма да завършат с postgres се свързва с нова основна версия на libicu , стига а) да не актуализирате пакетите PostgreSQL, или б) пакетите на PostgreSQL все още са свързани със същата основна версия на ICU, както преди. Опаковците ще трябва да внимават, за да поддържат това правилно, но това не би трябвало да е твърде проблематично на практика.
  • Когато големи надстройки на пакет и операционна система променят версията на съпоставяне, имаме начин да открием това и да предупредим потребителя. В момента просто предупреждаваме и предлагаме някои насоки и инструменти, за да коригираме нещата, но в бъдеще може да прецизираме и автоматизираме това допълнително.

(За да направите това по-ясно за пакетиращите:В стабилен клон на вашата операционна система не трябва да променяте основната версия на ICU, с която е свързан даден набор пакети PostgreSQL.)

Използване на ICU

За да можете да използвате това, PostgreSQL трябва да бъде изграден изрично с поддръжка на ICU. Когато създавате от източник, използвайте ./configure --with-icu заедно с други желани опции. Очакваме повечето големи двоични пакети също да предлагат това по подразбиране. Когато това е направено, базираните на ICU съпоставяния се предлагат заедно с базираните на libc съпоставяния, които предлагаха предишни издания. (Така че изграждането с поддръжка на ICU не премахва поддръжката за съпоставяне на libc; двете съществуват заедно.) Проверете документацията за подробности как да изберете базирано на ICU съпоставяне спрямо базирано на libc. Например, ако по-рано сте посочили

CREATE TABLE ... (... x text COLLATE "en_US" ...)

сега може да го направите

CREATE TABLE ... (... x text COLLATE "en-x-icu" ...)

Това трябва да ви даде приблизително същото видимо от потребителите поведение, както преди, с изключение на това, че вашата база данни ще бъде по-устойчива на бъдещето, когато става въпрос за надграждане. (В Linux/glibc редът на сортиране трябва да е почти същият, но може да има малки разлики в някои детайли. Ако обаче използвате операционна система, чиято C библиотека изобщо не поддържа Unicode съпоставяне, като macOS или по-стари версии на FreeBSD, тогава това ще бъде голяма промяна — към по-добро.)

Понастоящем поддръжката на ICU е налична само за изрично посочени съпоставяния. Съпоставянето по подразбиране в база данни все още винаги се предоставя от библиотеката C. Справянето с това е бъдещ проект.

Ако надстроите такава база данни чрез pg_upgrade например към нова инсталация на PostgreSQL, която е свързана с по-нова основна версия на ICU, която е променила версията за съпоставяне на това съпоставяне, което използвате, тогава ще получите предупреждение и ще трябва да коригирате например всички индекси, които зависят от съпоставяне. Инструкции за това също са в документацията.

Съкратени клавиши

Така че тази промяна ще осигури някои много важни подобрения за дългосрочна стабилност на системата от база данни. Но ICU също е подобрение спрямо системната библиотека C в други области.

Например, PostgreSQL B-дърветата могат да съхраняват така наречените съкратени ключове, за да подобрят производителността и съхранението. За типове данни с текстов низ, със стандартната библиотека C, ще изчислим тези съкратени ключове, използвайки strxfrm() функция. Въпреки това, ние научихме, че много C библиотеки имат различни грешки и неправилно поведение, които правят този подход ненадежден. Така че оптимизацията на съкратените ключове в момента е деактивирана за низови типове данни. С ICU можем да използваме еквивалентните API извиквания и да изчисляваме съкратени ключове по начин, който смятаме, че е надежден и стабилен. Така че има възможни подобрения в производителността и от този ход.

Още съпоставяне

Освен тези вътрешни подобрения на здравина и производителност, има и някои нови функционалности, насочени към потребителите.

За някои езици на практика може да има значение повече от един ред на сортиране. (Това може да ви помогне да започнете.) Един пример е, че за немски има стандартен ред на сортиране, който се използва за повечето цели, и ред на сортиране в „телефонен указател“, който се използва за списъци с имена. Стандартната библиотека C предоставя само един от тези варианти (вероятно първият). Но ако искате да напишете приложение, което правилно сортира, да речем, имената на продукти и имената на клиентите, трябва да можете да използвате и двете.

Например, примерът от немската Wikipedia вече може да бъде възпроизведен с PostgreSQL:

CREATE TABLE names (name text);

INSERT INTO names
    VALUES ('Göbel'), ('Goethe'), ('Goldmann'), ('Göthe'), ('Götz');

=> SELECT name FROM names ORDER BY name COLLATE "de-u-co-standard-x-icu";
   name
----------
 Göbel
 Goethe
 Goldmann
 Göthe
 Götz

=> SELECT name FROM names ORDER BY name COLLATE "de-u-co-phonebk-x-icu";
   name
----------
 Göbel
 Goethe
 Göthe
 Götz
 Goldmann

=> SELECT name FROM names ORDER BY name COLLATE "de-AT-u-co-phonebk-x-icu";
   name
----------
 Goethe
 Goldmann
 Göbel
 Göthe
 Götz

(С glibc, COLLATE "de_DE" и COLLATE "de_AT" наистина върне първата поръчка.)

Един интересен начин за комбиниране на няколко функции може да бъде използването на домейни за моделиране на гореспоменатата разлика между имената на продукти и имената на клиентите:

CREATE DOMAIN product_name AS text COLLATE "de-u-co-standard-x-icu";
CREATE DOMAIN person_name AS text COLLATE "de-u-co-phonebk-x-icu";

(Това е само пример. Разбира се, можете да прикачите и тези COLLATE клаузи към дефинициите на колони директно или да ги използват в заявки.)

Още повече съпоставяния

И накрая, и това очевидно е това, което светът чакаше, сега има начин за правилно сортиране на емоджита. Това е от съществено значение, за да сте сигурни, че всичките ви лица на котката са в правилния ред. Сравнете

=# SELECT chr(x) FROM generate_series(x'1F634'::int, x'1F644'::int) AS _(x)
       ORDER BY chr(x) COLLATE "und-x-icu";
 chr
-----
 😴
 😵
 😶
 😷
 😸
 😹
 😺
 😻
 😼
 😽
 😾
 😿
 🙀
 🙁
 🙂
 🙃
 🙄

с

=# CREATE COLLATION "und-u-co-emoji-x-icu" (provider = icu, locale = 'und-u-co-emoji');
=# SELECT chr(x) FROM generate_series(x'1F634'::int, x'1F644'::int) AS _(x)
       ORDER BY chr(x) COLLATE "und-u-co-emoji-x-icu";
 chr
-----
 🙂
 🙃
 😶
 🙄
 😴
 😷
 😵
 🙁
 😺
 😸
 😹
 😻
 😼
 😽
 🙀
 😿
 😾

Да, всъщност има стандарт за това.

Още предстои

Това е само началото. ICU предлага много функционалност в тази област, която все още не излагаме чрез PostgreSQL. Има опции за сортиране независимо от главните букви, сортиране без значение на акцентите и напълно персонализиране на сортиране. Потърсете ги в бъдещи издания на PostgreSQL.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. java.lang.ClassNotFoundException:org.postgresql.Driver, Android

  2. Еволюция на отказоустойчивостта в PostgreSQL

  3. Проверете дали NULL съществува в Postgres масива

  4. Как да прехвърля низ към цяло число и да имам 0 в случай на грешка при прехвърлянето с PostgreSQL?

  5. Постоянен UUID в PostgreSQL с помощта на JPA