citext
сохраняется как ввод, без преобразования в нижний регистр.Это также верно для хранения в качестве ключей индекса b-дерева.
Волшебство происходит в функции сравнения для citext
:
/*
* citextcmp()
* Internal comparison function for citext strings.
* Returns int32 negative, zero, or positive.
*/
static int32
citextcmp(text *left, text *right, Oid collid)
{
char *lcstr,
*rcstr;
int32 result;
/*
* We must do our str_tolower calls with DEFAULT_COLLATION_OID, not the
* input collation as you might expect. This is so that the behavior of
* citext's equality and hashing functions is not collation-dependent. We
* should change this once the core infrastructure is able to cope with
* collation-dependent equality and hashing functions.
*/
lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
result = varstr_cmp(lcstr, strlen(lcstr),
rcstr, strlen(rcstr),
collid);
pfree(lcstr);
pfree(rcstr);
return result;
}
Так что да, это должно повлечь за собой некоторые накладные расходы.Насколько это дорого, также будет зависеть от параметров сортировки базы данных по умолчанию.
Я продемонстрирую это, используя запрос без индекса.Я использую немецкое сопоставление:
SHOW lc_collate;
lc_collate
------------
de_DE.utf8
(1 row)
Первое использование text
:
CREATE TABLE large_text(t text NOT NULL);
INSERT INTO large_text
SELECT i||'text'
FROM generate_series(1, 1000000) AS i;
VACUUM (FREEZE, ANALYZE) large_text;
\timing on
SELECT * FROM large_text WHERE t = TEXT 'mama';
t
---
(0 rows)
Time: 79.862 ms
Теперь тот же эксперимент с citext
:
CREATE TABLE large_citext(t citext NOT NULL);
INSERT INTO large_citext
SELECT i||'text'
FROM generate_series(1, 1000000) AS i;
VACUUM (FREEZE, ANALYZE) large_citext;
\timing on
SELECT * FROM large_citext WHERE t = CITEXT 'mama';
t
---
(0 rows)
Time: 567.739 ms
Итакcitext
примерно в семь раз медленнее.
Но не забывайте, что каждый из этих экспериментов выполнял последовательное сканирование с миллионами сравнений.
Если вы используете индекс, разница не будетбыть заметным:
CREATE INDEX ON large_text (t);
Time: 5443.993 ms (00:05.444)
SELECT * FROM large_text WHERE t = CITEXT 'mama';
t
---
(0 rows)
Time: 1.867 ms
CREATE INDEX ON large_citext (t);
Time: 28009.904 ms (00:28.010)
SELECT * FROM large_citext WHERE t = CITEXT 'mama';
t
---
(0 rows)
Time: 1.988 ms
Вы видите, что CREATE INDEX
занимает гораздо больше времени для столбцов citext
(он должен выполнять много сравнений), но запросы занимают примерно то же время.
Причина в том, что вам нужно всего лишь несколько сравнений, если вы используете сканирование индекса: для каждого из 2-3 блоков индекса, к которым вы обращаетесь, вы выполняете двоичный поиск, и вам, возможно, придется повторно проверить строку таблицынайдено в случае сканирования индекса растрового изображения.