|   |   | 
| 
 | как ускорить запрос | ☑ | ||
|---|---|---|---|---|
| 0
    
        GANR 31.08.23✎ 12:56 | 
        Всем добрый день. Как построить индекс, чтобы запрос работал быстрее??
 -- установил расширения CREATE EXTENSION IF NOT EXISTS pg_trgm; CREATE EXTENSION IF NOT EXISTS btree_gin; -- построил составной gin индекс DROP INDEX IF EXISTS idx_gin_svjul_ltrim_inn_id; CREATE INDEX IF NOT EXISTS idx_gin_svjul_ltrim_inn_id ON svjul USING gin (ltrim(data ->> 'INN') gin_trgm_ops, id); -- запрос к таблице (размер более 100 Гб) SELECT * FROM svjul svjul1 WHERE ltrim(svjul1.data ->> 'INN') ilike '7839074221%' ORDER BY svjul1.id ASC LIMIT 20 OFFSET 0; -- ожидаемый результат: select выше работает быстро -- фактический результат: select выше работает мелденно и в плане запроса не видно срабатывания индекса | |||
| 1
    
        Волшебник 31.08.23✎ 13:00 | 
        уберите звёздочку
 уберите ltrim Вытащите INN в отдельное поле таблицы | |||
| 2
    
        GANR 31.08.23✎ 13:01 | 
        (1) Ни запрос, ни структуру таблицы менять нельзя. В этом то и прикол.     | |||
| 3
    
        asady 31.08.23✎ 13:18 | 
        В SELECT * FROM svjul svjul1 
 svjul и svjul1 = это две таблицы или svjul1 - алиас таблицы svjul ? | |||
| 4
    
        stopa85 31.08.23✎ 13:20 | 
        (0) хоть бы сказал, что за СУБД.     | |||
| 5
    
        Волшебник 31.08.23✎ 13:22 | 
        (3) очевидно да
 (4) PostgreSQL, судя по префиксу "pg" и попытке индексировать json-поле | |||
| 6
    
        stopa85 31.08.23✎ 13:25 | 
        (5) тогда где комментарий про VACUUM FULL?
 (0) Нужен explain без этого никак | |||
| 7
    
        GANR 31.08.23✎ 13:35 | 
        (3) (4) подтверждаю слова (5)     | |||
| 8
    
        GANR 31.08.23✎ 13:38 | 
        (6) появилось предположение, что постгрес при сортировке по id решает использовать первичный ключ вместо индекса (коим id является)
 Index Scan using svjul_pkey on svjul as svjul Filter: (ltrim((data ->> 'INN'::text)) ~~* '7839074221%'::text) сейчас попробую изменить order by, может быть подмена первичного ключа спасет отца русской демократи | |||
| 9
    
        GANR 31.08.23✎ 13:40 | 
        (6) (5) я в (8) был прав, стоило мне заменить в секции ORDER BY id на другое поле и запрос заработал быстро!!
 SELECT * FROM svjul WHERE ltrim(data ->> 'INN') ilike '7839074221%' ORDER BY created ASC LIMIT 20 OFFSET 0; | |||
| 10
    
        stopa85 31.08.23✎ 13:51 | 
        А какое количество строк он возвращает и ожидает вернуть, где оценки?     | |||
| 11
    
        GANR 31.08.23✎ 13:56 | 
        (10) По одному ИНН 1-3 записи, LIMIT 20 стоит ограничитель, вот только без составного индекса этот ограничитель будет работать медленно. Видимо придется добавить колонку id1, которую сделать первичным ключом, а по id построить просто индекс. Не знаю прокатит ли такое.     | |||
| 12
    
        stopa85 31.08.23✎ 14:34 | 
        (10) У вас какой-то кастрированный explain.
 Вот у меня какой (из заббикса табличка) explain select * from history where itemid = 42259 order by clock limit 20; QUERY PLAN ------------------------------------------------------------------------------------------- Limit (cost=0.43..73.34 rows=20 width=24) -> Index Scan using history_pkey on history (cost=0.43..53292.28 rows=14620 width=24) Index Cond: (itemid = 42259) (3 rows) | |||
| 13
    
        GANR 31.08.23✎ 14:54 | 
        (12) суть проста - scan using svjul_pkey вместо нужного мне индекса вот и всё     | |||
| 14
    
        H A D G E H O G s 31.08.23✎ 15:14 | 
        Нихера не понятно, но очень интересно.
 Руки бы оторвать этим любителям сокращений. select * - вот причина. Поменяй на select INN | |||
| 15
    
        GANR 31.08.23✎ 15:21 | 
        (14) это мимо     | |||
| 16
    
        GANR 31.08.23✎ 15:22 | 
        Ответ в (9). Другой вопрос как элегантнее решить проблему     | |||
| 17
    
        H A D G E H O G s 31.08.23✎ 15:29 | 
        (15) Как скажешь     | |||
| 18
    
        H A D G E H O G s 31.08.23✎ 15:33 | 
        Если считаешь, что твоя сортировка волшебным образом заставляет использоваиь некластерный индекс - ну так выбери во временную таблицу, а потом досортируй как надо.     | |||
| 19
    
        H A D G E H O G s 31.08.23✎ 15:37 | 
        Скорее всего ты просто прогрел кэш и запрос все также шарашит по кластерному индексу, ведь ему нужны остальные поля для select *, которых нет в некластерном и за которыми надо сходить по ridlookup. Да, limit скорее всего позволит это сделать только не более 20 раз, но так ли умен оптимизатор pg.     | |||
| 20
    
        GANR 31.08.23✎ 15:37 | 
        (18) запрос менять нельзя в том то и проблема     | |||
| 21
    
        H A D G E H O G s 31.08.23✎ 15:40 | 
        (20) конкурсы все интереснее. Ну ты план запроса то хоть собери для
 1) ORDER BY created 2) Select inn Чтобы понимать картину | |||
| 22
    
        H A D G E H O G s 31.08.23✎ 15:41 | 
        (20) добавь в твой индекс все поля запроса по include     | |||
| 23
    
        H A D G E H O G s 31.08.23✎ 15:41 | 
        **все поля таблицы     | |||
| 24
    
        Garykom 31.08.23✎ 16:30 | 
        Каким местом извлечение из jsonb в текст, затем ltrim а затем еще и ilike
 Может работать быстро? | |||
| 25
    
        Kesim 31.08.23✎ 16:36 | 
        (0) проблема в том что не по-русски написано)))     | |||
| 26
    
        GANR 31.08.23✎ 17:36 | 
        (24) Может, это ведь GIN индекс как раз для ilike. Ну а если бы ilike не было то и btree сгодился бы.     | |||
| 27
    
        Garykom 31.08.23✎ 17:43 | 
        >CREATE INDEX IF NOT EXISTS idx_gin_svjul_ltrim_inn_id ON svjul USING gin (ltrim(data ->> 'INN') gin_trgm_ops, id);
 не нравится мне что индекс по вычисляемому полю как sql поймет что один ltrim(data ->> 'INN' равен другому ltrim(data ->> 'INN' да еще для ilike ? | |||
| 28
    
        Garykom 31.08.23✎ 17:45 | 
        (27)+ имхо делай ты отдельную табличку с INN и используй ее     | |||
| 29
    
        GANR 31.08.23✎ 17:52 | 
        (27) Легко понимает, если я меняю первичный ключ с id на другую колонку. И запрос из 0 работает быстро. Вот только теперь выяснено, что приложение каким то боком подхватывает новый первичный ключ строит по нему другой order by и снова получается зависание. Получается замена первичного ключа не катит. Как-то статистику покрутить может можно??     | |||
| 30
    
        GANR 31.08.23✎ 17:52 | 
        (29) к (28)     | |||
| 31
    
        GANR 31.08.23✎ 17:55 | 
        (28) к сожалению запрос формирую не я, а стороннее приложение... так бы давно перекроил запрос и забыл как страшный сон     | |||
| 32
    
        Garykom 31.08.23✎ 17:55 | 
        а если убрать id?
 CREATE INDEX IF NOT EXISTS idx_gin_svjul_ltrim_inn_id ON svjul USING gin (ltrim(data ->> 'INN') gin_trgm_ops); | |||
| 33
    
        Garykom 31.08.23✎ 18:04 | 
        (32)+ гм не понял а gin_trgm_ops это что?     | |||
| 34
    
        Garykom 31.08.23✎ 18:38 | 
        (33)+ понял указание на триграмный     | |||
| 35
    
        GANR 31.08.23✎ 22:41 | 
        (32) тогда он сможет ускорить запрос без order by id - не катит 
 (34) полнотекстовый мудреж | |||
| 36
    
        GANR 31.08.23✎ 22:41 | 
        (35) опечатка, наоборот НЕ сможет     | |||
| 37
    
        GANR 31.08.23✎ 22:43 | 
        Из за order by id     | |||
| 38
    
        Garykom 31.08.23✎ 23:10 | 
        сделай view     | |||
| 39
    
        Djelf 01.09.23✎ 07:47 | 
        А может попробовать убрать "USING gin"?
 Вроде этот индекс не так работает, как хотелось бы (0) https://postgrespro.ru/docs/postgrespro/9.5/datatype-json#json-indexing | |||
| 40
    
        GANR 01.09.23✎ 11:33 | 
        (38) не пойдет - приложуха с view работать не сможет
 (39) не пойдет - кроме gin с ilike не работет ничего Как ни странно, я добавил колонку id1, перекинул первичный ключ с id на id1, затем перекинул ключ обратно на id и удалил id1 - в итоге запрос начал подхватывать мой индекс gin вместо первичного ключа, каким образом мои манипуляции могли повлиять знает кто-нибудь? | |||
| 41
    
        Djelf 01.09.23✎ 11:51 | 
        (40) Хм, проверил онлайн запросом, ilike сработал без gin.
 Откуда сведения? В документации нет таких ограничений https://postgrespro.ru/docs/postgresql/9.6/functions-matching | |||
| 42
    
        GANR 01.09.23✎ 12:05 | 
        (41) он сработал, но только на больших объемах то медленно будет, в нашем случае это = не работает     | |||
| 43
    
        GANR 01.09.23✎ 14:27 | 
        Удалось добиться ускорения поиска по ИНН вот такими заклинаниями:
 CREATE INDEX IF NOT EXISTS idx_gin_svjul_ltrim_id_inn ON svjul USING gin (id, ltrim(data ->> 'INN') gin_trgm_ops); ALTER INDEX idx_gin_svjul_ltrim_id_inn ALTER COLUMN 2 SET STATISTICS 1000; ANALYZE svjul; | |||
| 44
    
        GANR 01.09.23✎ 14:29 | 
        (38) (39) (21) (10) (1) благодарю за содействие. Хотелось бы поподробнее до каких пор эта штука у меня проработать может ещё и если недолго то как продлить?     | |||
| 45
    
        ansh15 01.09.23✎ 16:57 | 
        (44) Многопоточность как-нибудь применяется? Скажем, max_parallel_workers_per_gather=6
 и в плане запроса Workers Planned: 6 Workers Launched: 6 -> Parallel Seq Scan и т.д. | |||
| 46
    
        GANR 01.09.23✎ 17:57 | 
        (45) Даже и не знаю. А как это на план запроса влияет?     | |||
| 47
    
        ansh15 01.09.23✎ 19:05 | 
        (46) Здесь есть примеры https://habr.com/ru/articles/305662/
 Статья старенькая, но все же.. | 
| Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |