Nano Hash - криптовалюты, майнинг, программирование

Почему Postgres тратит так много времени на сканирование только индекса

Версия Postgres: 12

Запрос:

ОБЪЯСНИТЬ (АНАЛИЗ ИСТИНА, ПОДРОБНОЕ ОПИСАНИЕ ИСТИНА, СТОИМОСТЬ ИСТИНА, БУФЕРЫ ИСТИНА, ВРЕМЯ ИСТИНА) ВЫБЕРИТЕ МИН(id), МАКС(id) ИЗ public.hotel_slot_inventory ГДЕ ( updated_at ›= '2021-03-02 13:30:03' И updated_at ‹ '2021-03-03 06:15:19.127884' );

План запроса:

 Result  (cost=512.17..512.18 rows=1 width=8) (actual time=65556.920..65556.926 rows=1 loops=1)
   Output: $0, $1
   Buffers: shared hit=370 read=454012 written=8
   I/O Timings: read=62266.717 write=0.194
   InitPlan 1 (returns $0)
     ->  Limit  (cost=0.57..256.09 rows=1 width=4) (actual time=65251.998..65252.001 rows=1 loops=1)
           Output: hotel_slot_inventory.id
           Buffers: shared hit=1 read=453546 written=8
           I/O Timings: read=61967.042 write=0.194
           ->  Index Only Scan using hotel_slot_inventory_id_updated_at_idx on public.hotel_slot_inventory  (cost=0.57..3291347.07 rows=12881 width=4) (actual time=65251.996..65251.997 rows=1 loops=1)
                 Output: hotel_slot_inventory.id
                 Index Cond: ((hotel_slot_inventory.id IS NOT NULL) AND (hotel_slot_inventory.updated_at >= '2021-03-02 13:30:03'::timestamp without time zone) AND (hotel_slot_inventory.updated_at < '2021-03-03 06:15:19.127884'::timestamp without time zone))
                 Heap Fetches: 1
                 Buffers: shared hit=1 read=453546 written=8
                 I/O Timings: read=61967.042 write=0.194
   InitPlan 2 (returns $1)
     ->  Limit  (cost=0.57..256.09 rows=1 width=4) (actual time=304.902..304.903 rows=1 loops=1)
           Output: hotel_slot_inventory_1.id
           Buffers: shared hit=369 read=466
           I/O Timings: read=299.674
           ->  Index Only Scan Backward using hotel_slot_inventory_id_updated_at_idx on public.hotel_slot_inventory hotel_slot_inventory_1  (cost=0.57..3291347.07 rows=12881 width=4) (actual time=304.899..304.899 rows=1 loops=1)
                 Output: hotel_slot_inventory_1.id
                 Index Cond: ((hotel_slot_inventory_1.id IS NOT NULL) AND (hotel_slot_inventory_1.updated_at >= '2021-03-02 13:30:03'::timestamp without time zone) AND (hotel_slot_inventory_1.updated_at < '2021-03-03 06:15:19.127884'::timestamp without time zone))
                 Heap Fetches: 3892
                 Buffers: shared hit=369 read=466
                 I/O Timings: read=299.674
 Planning Time: 0.229 ms
 Execution Time: 65556.982 ms
(28 rows)

Мы видим, что это простое сканирование только индекса заняло 65556,982 мс. Большую часть времени занимает InitPlan 1 65251,997 мс. Почему так? ему просто нужно было получить первую запись из индекса btree в прямом и обратном поиске соответственно, поскольку запрос запрашивает Min и Max... не нужно извлекать все совпадающие записи из индекса btree
FYI: Вакуум не сильно помог.

Изменить детали раздувания индекса:

реальный_размер: 3751411712 = 3,49 ГБ

дополнительный_размер: 470237184 = 448 МБ

дополнительное_отношение: 12,53

Коэффициент заполнения: 90

bloat_size: 107053056 = 102 МБ

раздувание_отношение: 2,85

Размер таблицы: bloat_size: 475283456 = 453 МБ

раздувание_отношение: 5,088


  • Пожалуйста, не открывайте разные вопросы по одной и той же проблеме: stackoverflow.com/questions/66452891/ 03.03.2021
  • @S-Man: В обеих ветках я задаю разные вопросы. Это было рекомендовано мне ранее, и я нашел это разумным. 03.03.2021
  • Вы должны дать нам определение индекса, а не заставлять нас гадать. 03.03.2021
  • Вы не ответили на вопросы, запрашивающие дополнительную информацию по повторяющемуся вопросу... Я попросил вас проверить статистику раздувания индекса, потому что это ненормально, что для получения одной строки требуется прочитать 453546 буферов. 03.03.2021
  • @bobflux: только что сделал 04.03.2021

Ответы:


1

Ваш индекс должен начинаться с (id, updated_at...). Обратите внимание, что этот индекс не может считывать только рассматриваемый диапазон времени, потому что это не первый столбец в индексе, а столбец, который является первым, не определяется равенством. Итак, вы начинаете сканировать весь индекс, пока не найдете строку, удовлетворяющую условию времени. Я называю это индексным фильтром. Очевидно, для этого потребовалось много сканирования в прямом направлении, и это было бы связано с тем, что ни одна из записей в этом конце индекса не удовлетворяет условию времени. Планировщик, однако, не понимает этого факта, он думает, что найдет 12881 строку, равномерно разбросанную по всему индексу. Не все на одном конце.

В отличие от обычного (внеиндексного) фильтра, план не сообщает, сколько строк было оценено, а затем удалено с помощью внутрииндексного фильтра. Это оставляет планы немного трудно интерпретировать.

Есть два доказательства этой интерпретации. Во-первых, предельные узлы вообще существуют, даже если в вашем запросе не указан предел. Это может быть только в поддержку минимальных и максимальных агрегатов. Другой - это внедрение IS NOT NULL в условие индекса, когда этого не было в вашем запросе. Я не знаю, почему это происходит, но это указывает на фильтр внутри индекса (или иногда на частичный индекс), а не на обычное использование индекса.

03.03.2021
  • Да, мой индекс включен (id, updated_at). Я создал его таким образом, потому что ранее я создал его как (updated_at,id), но запрос вообще не использовал это, и запрос работал очень медленно в течение многих минут, поэтому я вернул позицию индекса, а затем он в конечном итоге использовал индекс, но это медленный. Не уверен, как это исправить 04.03.2021
  • пожалуйста, помогите здесь. 04.03.2021
  • Индекс для (updated_at,id) должен быть быстрым для этого временного диапазона, если предположить, что статистика точна и в этом временном диапазоне действительно всего 12881 строка. Если у вас есть вопрос по этому поводу, вы должны опубликовать его. (а не беспорядочный беспорядок, который вы опубликовали на прошлой неделе, когда вы создавали индексы для таблиц, которые даже не были теми, которые вы запрашивали.) 04.03.2021
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..


    © 2024 nano-hash.ru, Nano Hash - криптовалюты, майнинг, программирование