находится чуть больше 1 млн строк. Сама таблица представляет из себя нечто следующее:
                  
                  
                  
                  
                  
                  
                  
                  
                  CREATE TABLE my_table (
                  
                  
                       id                                 NOT NULL PRIMARY KEY,
                  
                  
                       ...
                  
                  
                       search_title                 VARCHAR NOT NULL,
                  
                  
                       another_search_field  VARCHAR NOT NULL,
                  
                  
                      deleted                         TIMESTAMP
                  
                  
                  )
                  
                  
                  
                  
                  
                  
                  
                  
                  Другие поля просто опустил за ненадобностью в данном вопросе. Так вот, у меня там был обычный составной индекс для (search_title, another_search_field). Начал анализировать планировщика запросов и понял, что индексы у меня не используются. Важно уточнить, что у меня в запросах имеется LIKE оператор, т.е это выглядит примерно так:
                  
                  
                  
                  
                  
                  
                  
                  
                  SELECT * FROM my_table WHERE search_title LIKE '%some title%' AND another_search_field = '...';
                  
                  
                  
                  
                  
                  
                  
                  
                  В общим, анализ (EXPLAIN (analyze,verbose,timing,costs,buffers)) мне показывает, что у меня используется последовательный поиск для запроса
                  
                  
                  
                  
                  
                  Запрос:
                  
                  
                  
                  
                  
                  
                  
                  
                  SELECT id FROM my_table WHERE search_title LIKE '%title%'
                  
                  
                  
                  
                  
                  
                  
                  
                  Результат:
                  
                  
                  
                  
                  
                  
                  
                  
                  Seq Scan on public.my_table  (cost=0.00..40873.66 rows=1052908 width=16) (actual time=0.050..7154.845 rows=1053013 loops=1)
                  
                  
                    Output: id
                  
                  
                    Filter: ((mt_table.search_title)::text  '%title%'::text)
                  
                  
                    Buffers: shared hit=192 read=27519
                  
                  
                  Planning Time: 0.069 ms
                  
                  
                  Execution Time: 13513.829 ms
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  
                  На всякий случай отключил последовательную прогонку, но в итоге результат всё равно такой, что индекс не используется. Понятное дело, что set enable_seqscan = off не форсит отмену последовательной прогонки. Но, похоже, что других вариантов нет для планировщика. И в том числе нет варианта использовать индекс.
                  
                  
                  
                  
                  
                  
                  
                  
                  Seq Scan on public.my_table  (cost=10000000000.00..10000040873.66 rows=1052908 width=16) (actual time=24.158..7218.534 rows=1053013 loops=1)
                  
                  
                    Output: id
                  
                  
                    Filter: ((my_table.search_title)::text  '%title%'::text)
                  
                  
                    Buffers: shared read=27711 written=32
                  
                  
                  Planning:
                  
                  
                    Buffers: shared hit=11 read=5 dirtied=3 written=5
                  
                  
                  Planning Time: 0.730 ms
                  
                  
                  JIT:
                  
                  
                    Functions: 4
                  
                  
                  "  Options: Inlining true, Optimization true, Expressions true, Deforming true"
                  
                  
                  "  Timing: Generation 1.118 ms, Inlining 4.890 ms, Optimization 12.192 ms, Emission 6.884 ms, Total 25.084 ms"
                  
                  
                  Execution Time: 13776.353 ms
                  
                  
                  
                  
                  
                  
                  
                  
                  В итоге подумал, что проблема в том, что обычный индекс тут не особо уместен, попробовал создать GIN индекс. Потому что исходя из моих требований (поиск по LIKE) все филды текстовые, а значит и уместность, по идеи, должна быть.
                  
                  
                  
                  
                  
                  
                  
                  
                  CREATE INDEX trgm_idx ON my_table USING GIN (search_title gin_trgm_ops) WHERE deleted IS NULL;
                  
                  
                  Касаемо deleted, то у меня просто используется принцип soft-delete в приложении.
                  
                  
                  
                  
                  
                  
                  
                  
                  Короче, пробую опять. И результат тот же - индекс не используется. В итоге у меня сложилось ощущение, что я что-то упустил. Может GIN индекс тут неуместен? Может тестовые данные у меня не особо подходящие? Про второе следует уточнить, что я нагенерил 1мл записей, где в качестве поля search_title выступает следующий паттерн: UUID title UUID. Т.е условно говоря, должно быть большое кол-во страниц с повторяющимися данными для LIKE оператора. Потому что сейчас, что индекс есть (обычный или GIN), что его нет - одна репка, как говорится.
                  
                  
                
Ты что-то упустил. Позже скажу, что
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Интрига. Интересно узнать что именно упустил.
Для начала ты упустил, что индекс не должен всегда обязательно использоваться. Он используется только, если с ним запрос будет "быстрее" (на самом деле — будет с меньшей стоимостью выполнения)
Далее: Что является SARG-ом, а что нет: search_title LIKE '%some title%' - не SARG another_search_field = '...' - SARG Cледовательно SELECT id FROM my_table WHERE search_title LIKE '%title%' этому запросу индекс в принципе не нужен. Разве что использовать как покрывающий. Будет table scan Кажется, на все твои вопросы ответил.
SARG - это Search ARGument , выражение, которое может быть использовано для поиска (фильтрации) по индексу.
индекс для (search_title, another_search_field). — сюда не подходит никак, потому как ведущее поле не SARG. (не входит в SARG) Тут подошёл бы потенциально индекс (another_search_field) , но там надо ещё статистику смотреть
Да, возможно, что в твоей ситуацыи тэстовые данные не особо подходящие либо индэкс GIN неуместен. С другой стороны -- возможно, что вы что-то нетак делаете в запросе. Тем более, что вроде при похожых ситуацыях GIN-индэкс должэн использоваться. Точнее можно будет начать анализировать если вы покажыте точный \d для таблицы и запрос, а не какие-то странные и несовместимые друг с другом отрывки.
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Почему отрывки несовместимы? Я показал реальные запросы. Т.е у меня поиск по LIKE у текстового поля.
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Звучит разумно, но есть одно НО: https://niallburkley.com/blog/index-columns-for-like-in-postgres/ Почему в данной ситуации запрос смог стать SARG? И как его сделать таким? Потому что если я буду использовать не LIKE, а сравнение, то индекс все равно не будет использоваться.
Нет, дело не в данных
Я даже не буду ссылку смотреть, по LIKE индекс может использоваться , если в LIKE задаётся ПРЕФИКС значения. Если задаются инфиксы или суффиксы - то нет. У тебя задаётся ИНФИКС.
Ну и ссылка - надпись на заборе, ты или официальную документацию читай (ну или исходники), или своей головой думай.
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  А чем статья отличается от ответа на форуме или в чатике? Вопрос риторический. Филькина это грамота - уже другой вопрос. Можно тогда указать пункт в доке, где написано про совместимость LIKE оператора в контексте GIN индекса?
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  А можно поподробнее?
Заглянул таки в статью, Postgres uses trigrams to break down strings into smaller chunks and index them efficiently. The pg_trgm module supports GIST or GIN indexes and as of Postgres version 9.1 these indexes support LIKE/ILIKE queries. Если с триграммами, то это , конечно, другое совсем дело, но у тебя ТАКОЙ индек был построен?
И кстати - только сейчас заметил — ты если пишешь в индексе CREATE INDEX trgm_idx ON my_table USING GIN (search_title gin_trgm_ops) WHERE deleted IS NULL; то то же условие надо повторять и в запросе. Иначе индекс не сможет быть задействован.
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  >USING GIN (search_title gin_trgm_ops)
Откуда я знаю, почему у тебя получились несовместимые отрывки?
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Откуда я знаю, что ты понимаешь под несовместимыми отрывками?
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Хм, хороший поинт про условие индекса, да. Запрос стал пошустрее в два раза. Но теперь он решил выбрал finalize aggregate. И да, про условие с soft-delete вылетело из головы, так как запрос делается другой библиотекой, там у нас своя модификация JPA.
Как минимум -- твой запрос несовместим с индэксом WHERE deleted IS NULL.
Но вообще -- важнее что отрыки, которые трудно проверить, а не то, что они несовместимы.
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Ну да, про этот момент уже упомянул @MasterZiv , за что ему спасибо. Оказывается, в моей версии jpa затерся необходимый soft-delete предикат (where deleted is null). Но в остальном то что не совместимо? Хочется услышать конкретику.
Лучше выкинь ты этот where deleted is null потому что у тебя 90% данных будет под это подходить, нет смысла. Вот если делать индекс наоборот для поиска среди удалённых, там это может помочь.
Фиг его знает -- в остальном можэт и совместимо, однако проверять на отрыках всё равно малореально.
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Если бы я мог выкинуть. Этот геморрой идёт не от меня, увы. И вечно подобные выстрелы в колено происходят, если честно.
Из индэкса выкинь.
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Мы же тут не в клубе философов, которые обсуждают высокую материю. Кажется, проблему уже нашли. А не "ну у тебя запрос несовместим, а почему - ну фиг знает" 😉
Если вы тут не в клубе философов -- то это вашы личные трудности.
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Индексы создаются этой же либой.
Ну, это... Ну, у меня слов нет. В общем, ты можэшь жаться, секретничать и устраивать тут ЧГК сколько твоей душэ угодно -- но помешает добиться результата это именно тебе, если что.
Неужели ж JPA додумывается до того, чтобы на конкретной платформе протянуть в индекс условие WHERE ?
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Слушай, ну есть же такая штука как NDA. Я считаю, что описал необходимый минимум. Если не согласен - то уточняй тогда где именно, я дополню вопрос.
В триграм индэкс, хе-хе. До чего дошёл противоестественный интеллект!
Проблема совсем не в этом, в том, что ты пока не понимаешь, когда и зачем в СУБД используются индексы. Ты думаешь — индекс - значит, будет быстро. Это не так. Вот проблема. И мы её не решили.
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Там ко всему условие с soft-delete применяется. В общем, суть в том, что индексы не должны действовать на те сущности, которые "удалены". Т.е у которых поле deleted проставлено.
Ну, ты сейчас под своё NDA начинаешь подтягивать вызовы своей "библиотеки", которые создают индэксы. Не, опять жэ, флаг в руки...
И что за JPA там у вас?
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Так. Допустим. >Вот проблема. И мы её не решили А что ты именно хочешь решить?
К тебе тоже относится
И да, если всё плохо с NDA -- ну, создай testcase искуственный чтобы своё понимание прокачать. В общем, у людей жэлания париться и угадывать что там у тебя образовалось между многоточиями и что ты отрезал от какого запроса -- будет гораздо меньшэ, чем просто повторить какой-то случай и посоветовать, что происходит.
Это резонное утверждение.
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Не понимаю о чем ты говоришь. Я лишь отвечаю на вопросы, которые относятся к моему первому вопросу. Т.е у меня нет цели разводить смуту. А именно разобраться.
Я могу и вообще отсюда выйти, чотам. Мест, где удаль молодецкую показать пока хватает.
Александр, ну ладно, вопрос решили? Всё понял?
Да нет, я б не хотел...
 Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                      
                      
                        
                          Aleksandr
                          
                        
                      
                    
                    
                    
                    
                      Автор вопроса
                    
                    
                  Да, конечно. За это и спасибо :)
Ты там спроси у того, кто такое "условие" ставит -- он головкой в детстве не стукался? Нахера он своими политическими требованиями лезет в потроха СУБД, в разработке которых он, судя по всему, ничего не понимает?
Это может делать библиотека - реализация JPA автоматом, без программирования.
Да не важно, кто физически это делает -- библиотека или программист. Важно -- почему политические вопросы просочились настолько в нижний уровень системы хранения.
Ты ещё учти, что JPA можно наконфигурировать так, чтобы индексы оно не создавало вообще, и создавать их руками.
Обсуждают сегодня