Когда использовать многостолбцовые индексы? - PullRequest
0 голосов
/ 07 декабря 2018

У меня есть следующая таблица с примерно 10 миллионами строк

CREATE TABLE "autocomplete_books"
(
    id uuid PRIMARY KEY DEFAULT uuid_generate_v4 (),
    author_id uuid NOT NULL REFERENCES "author"(id) ON DELETE CASCADE,
    language VARCHAR(30) NOT NULL,
    name VARCHAR(100) NOT NULL,
    importance_rank SMALLINT NOT NULL DEFAULT 1
);

У меня есть следующий запрос

SELECT DISTINCT ON (author_id)
    author_id,
    similarity(name, $1) as score,
    language, name, importance_rank
FROM
    "autocomplete_books"
WHERE
    $1 % name AND language IN ($2, $3, $4)
ORDER BY
    author_id, score DESC, importance_rank DESC
LIMIT
    10

Я в основном запрашиваю сходство, так как это конечная точка автозаполнения, поэтомуУ меня есть индекс триграммы по имени.Я также сортирую по некоторым другим областям.Я не уверен, как поле score будет смешиваться с другими моими индексами и лучше ли иметь составной индекс, например,

Опция 1

CREATE INDEX ON "autocomplete_books" USING GIN (name gin_trgm_ops);
CREATE INDEX ON "autocomplete_books" USING BTREE (author_id, language, importance_rank DESC);

Или, если мне нужно разбить их так:

Вариант 2

CREATE INDEX ON "autocomplete_books" USING GIN (name gin_trgm_ops);
CREATE INDEX ON "autocomplete_books" USING BTREE (author_id, language, importance_rank DESC);
CREATE INDEX ON "autocomplete_books" USING BTREE (language);
CREATE INDEX ON "autocomplete_books" USING BTREE (importance_rank DESC);

Вот вывод explain analyze, выполненный на 220 тыс. Строк сследующий индекс

CREATE INDEX ON "autocomplete_books" USING BTREE (author_id, language);
CREATE INDEX ON "autocomplete_books" USING BTREE (importance_rank DESC);

-

Limit  (cost=762.13..762.38 rows=50 width=82) (actual time=12.230..13.024 rows=50 loops=1)
  ->  Unique  (cost=762.13..763.23 rows=217 width=82) (actual time=12.223..12.686 rows=50 loops=1)
        ->  Sort  (cost=762.13..762.68 rows=220 width=82) (actual time=12.216..12.373 rows=50 loops=1)
              Sort Key: author_id, ((similarity((name)::text, \'sale\'::text)) DESC, importance_rank DESC
              Sort Method: quicksort  Memory: 45kB
              ->  Bitmap Heap Scan on "books_autocomplete" mat  (cost=45.71..753.57 rows=220 width=82) (actual time=1.905..11.610 rows=149 loops=1)
                    Recheck Cond: (\'sale\'::text % (name)::text)
                    Rows Removed by Index Recheck: 2837
                    Filter: ((language)::text = ANY (\'{language1,language2,language3}\'::text[]))
                    Heap Blocks: exact=2078
                    ->  Bitmap Index Scan on "books_autocomplete_name_idx"  (cost=0.00..45.65 rows=220 width=0) (actual time=1.551..1.557 rows=2986 loops=1)
                          Index Cond: (\'sale\'::text % (name)::text)
Planning time: 13.976 ms
Execution time: 13.545 ms'

1 Ответ

0 голосов
/ 07 декабря 2018

Индекс поможет вам в сортировке, только если все выражения в предложении ORDER BY находятся в индексе, и вы не можете сделать это из-за второго выражения.

Кроме того, только индексы b-дерева полезны для поддержки ORDER BY.Теперь вы не можете объединять несколько индексов, когда хотите использовать ORDER BY, и вы говорите, что $1 % name - ваш самый избирательный критерий, поэтому вы, вероятно, хотите использовать индекс для этого.

Существует два способа:запрос может занять:

  1. Перейти к условию $1 % name с индексом GIN триграммы на name.Это то, что делает план выполнения в вашем вопросе.Тогда вам придется жить с этим Sort, потому что вы не можете использовать индекс для него.Опасность заключается в том, что при сканировании индекса растрового изображения будет найдено так много строк, что сканирование кучи растрового изображения будет довольно дорогим.

  2. Если существует индекс, который точно соответствует ORDER BYпредложение:

    CREATE INDEX ON autocomplete_books
       (author_id, score DESC, importance_rank DESC);
    

    вы можете сканировать индекс и извлекать строки в порядке ORDER BY, пока у вас не будет 10, соответствующих условию фильтра $1 % name.Опасность заключается в том, что поиск 10 строк может занять больше времени, чем ожидалось.

Попробуйте сначала только с одним индексом, затем только с другим индексом и выполните запрос с другими параметрами.для набора данных реалистичного размера, чтобы увидеть, что работает лучше всего.

Вы должны отбросить все остальные индексы, кроме этих двух, потому что они не принесут пользы для этого запроса.

Если одиниз двух стратегий - явный победитель, отбросьте другой индекс, чтобы оптимизатор не испытывал соблазна его использовать.В противном случае сохраните оба и надеемся, что оптимизатор выберет правильный в зависимости от параметров.

...