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

Как я могу создать индекс по столбцу широты/долготы, используя GIST в сочетании с логическим столбцом?

У меня есть такая таблица:

CREATE TABLE products (
  id INT,
  latitude numeric(9,6),
  longitude numeric(9,6),
  is_location_independent boolean
);

INSERT INTO products (id, latitude, longitude, is_location_independent) VALUES (1, 56.1508469,10.2128301,false);
INSERT INTO products (id, latitude, longitude, is_location_independent) VALUES (2,56.1508469,15.2128301,true);

Я хочу создать индекс, который эффективно охватывает следующий запрос:

SELECT COUNT(*) FROM products
  WHERE 
    (ST_DWithin( ST_GeographyFromText( 'SRID=4326;POINT(' || longitude || ' ' || latitude || ')' ), ST_GeographyFromText('SRID=4326;POINT(13.621700 45.940900)'), 80000 ) OR is_location_independent IS TRUE)

Я попытался создать:

CREATE INDEX CONCURRENTLY index_products_location
    ON products USING gist
    (st_geographyfromtext(((('SRID=4326;POINT('::text || longitude) || ' '::text) || latitude) || ')'::text), is_location_independent)
    TABLESPACE pg_default;

Но я получаю следующее исключение:

ERROR: data type boolean has no default operator class for access method "gist"

Теперь иметь индекс без комбинации с is_location_independent не получится. Без этого планировщик запросов решает выполнить последовательное сканирование таблицы, а в ней миллионы строк, поэтому это медленно (8 секунд).

Что я могу сделать?

P.S. PostgreSQL 11.

Обновить

Добавив следующие два индекса:

CREATE INDEX ON products USING gist (
   st_geographyfromtext(
      'SRID=4326;POINT(' || longitude || ' ' || latitude || ')'
   )
) WHERE is_location_independent;

а также

CREATE INDEX ON products USING btree (
   is_location_independent
);

И имея такие данные, как: is_location_independent: true => 1493 записи и is_location_independent: false => 1 359 200

Выполняя запрос, планировщик запросов фактически не использует GEO-индекс, который был бы действительно полезен для запроса...

"Finalize Aggregate  (cost=262104.14..262104.15 rows=1 width=8) (actual time=2297.030..2297.030 rows=1 loops=1)"
"  ->  Gather  (cost=262103.72..262104.13 rows=4 width=8) (actual time=2292.063..2667.239 rows=5 loops=1)"
"        Workers Planned: 4"
"        Workers Launched: 4"
"        ->  Partial Aggregate  (cost=261103.72..261103.73 rows=1 width=8) (actual time=2273.565..2273.566 rows=1 loops=5)"
"              ->  Parallel Index Scan using index_products_on_is_location_independent on products  (cost=0.43..261093.34 rows=4152 width=0) (actual time=12.878..2272.703 rows=4461 loops=5)"
"                    Filter: (((st_geographyfromtext((((('SRID=4326;POINT('::text || (longitude)::text) || ' '::text) || (latitude)::text) || ')'::text)) && '0101000020E6100000AED85F764F3E2B40386744696FF84640'::geography) AND ('0101000020E6100000AED85F764F3E2B40386744696FF84640'::geography && _st_expand(st_geographyfromtext((((('SRID=4326;POINT('::text || (longitude)::text) || ' '::text) || (latitude)::text) || ')'::text)), '80000'::double precision)) AND _st_dwithin(st_geographyfromtext((((('SRID=4326;POINT('::text || (longitude)::text) || ' '::text) || (latitude)::text) || ')'::text)), '0101000020E6100000AED85F764F3E2B40386744696FF84640'::geography, '80000'::double precision, true)) OR (is_location_independent IS TRUE))"
"                    Rows Removed by Filter: 257706"

Как видите, индексация работает неэффективно...

21.01.2020

Ответы:


1
CREATE INDEX ON products USING gist (
   st_geographyfromtext(
      'SRID=4326;POINT(' || longitude || ' ' || latitude || ')'
   )
) WHERE is_location_independent;

Разве предложение WHERE здесь не задом наперед? Какой смысл индексировать местоположения для точек, где местоположения не имеют значения?

Если я создам индекс с отрицательным WHERE, то с небольшим изменением вашего запроса я смогу заставить его использовать оба индекса с BitmapOr.

explain SELECT COUNT(*) FROM products WHERE 
(
    ST_DWithin( ST_GeographyFromText( 'SRID=4326;POINT(' || longitude || ' ' || latitude || ')' ), ST_GeographyFromText('SRID=4326;POINT(13.621700 45.940900)'), 800000 )
    AND 
    not is_location_independent
) 
OR is_location_independent;

Дает план

Aggregate  (cost=63.09..63.10 rows=1 width=8)
   ->  Bitmap Heap Scan on products  (cost=8.53..63.09 rows=2 width=0)
         Recheck Cond: ((st_dwithin(st_geographyfromtext((((('SRID=4326;POINT('::text || (longitude)::text) || ' '::text) || (latitude)::text) || ')'::text)), '0101000020E6100000AED85F764F3E2B40386744696FF84640'::geography, '800000'::double precision, true) AND (NOT is_location_independent)) OR is_location_independent)
         Filter: ((st_dwithin(st_geographyfromtext((((('SRID=4326;POINT('::text || (longitude)::text) || ' '::text) || (latitude)::text) || ')'::text)), '0101000020E6100000AED85F764F3E2B40386744696FF84640'::geography, '800000'::double precision, true) AND (NOT is_location_independent)) OR is_location_independent)
         ->  BitmapOr  (cost=8.53..8.53 rows=2 width=0)
               ->  Bitmap Index Scan on products_st_geographyfromtext_idx1  (cost=0.00..4.38 rows=1 width=0)
                     Index Cond: (st_geographyfromtext((((('SRID=4326;POINT('::text || (longitude)::text) || ' '::text) || (latitude)::text) || ')'::text)) && _st_expand('0101000020E6100000AED85F764F3E2B40386744696FF84640'::geography, '800000'::double precision))
               ->  Bitmap Index Scan on products_is_location_independent_idx  (cost=0.00..4.14 rows=2 width=0)
                     Index Cond: (is_location_independent = true)

Без ручного переписывания запроса, включающего явное «не is_location_independent» И, объединенное с функцией geography, планировщик не сможет понять, что он может использовать индекс.

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

Я создал 3 индекса ниже. Первые 2 используются в вашем исходном запросе, 1-й и 3-й используются в моей перезаписи. Я также сделал версию первого индекса, которая была отфильтрована только для WHERE is_location_indepedent, и эта версия будет использоваться вместо оригинала.

"products_is_location_independent_idx" btree (is_location_independent)
"products_st_geographyfromtext_idx" gist (st_geographyfromtext(((('SRID=4326;POINT('::text || longitude) || ' '::text) || latitude) || ')'::text))
"products_st_geographyfromtext_idx1" gist (st_geographyfromtext(((('SRID=4326;POINT('::text || longitude) || ' '::text) || latitude) || ')'::text)) WHERE NOT is_location_independent
22.01.2020
  • Это интересно. Итак, что же представляют собой два созданных вами индекса? 22.01.2020
  • Именно это сработало. Каким-то образом планировщик запросов не смог использовать индексы в комбинированном растровом изображении ИЛИ, если только первый не был создан с WHERE is_location_independent; Odd 27.01.2020

  • 2

    Нет смысла включать is_location_independent в индекс, так как у вас есть OR в условии WHERE.

    Есть две возможности:

    • Если во многих строках is_location_independent установлено в TRUE, PostgreSQL всегда будет использовать последовательное сканирование, поскольку оно является самым быстрым.

    • Если только в нескольких строках is_location_independent установлено в TRUE, создайте второй индекс: обычный индекс B-дерева только для is_location_independent.

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

    21.01.2020
  • Вы имеете в виду, что два индекса, один: CREATE INDEX ON products USING btree (is_location_independent) и один CREATE INDEX ON products USING gist ( st_geographyfromtext( 'SRID=4326;POINT(' || longitude || ' ' || latitude || ')' ) ) WHERE is_location_independent;, будут работать? для запроса? Мне интересно, должно ли последнее на самом деле быть WHERE is_location_independent IS NOT TRUE; вместо этого, верно? 21.01.2020
  • Данные такие: is_location_independent: true => 1493 записи и is_location_independent: false => 1359200 21.01.2020
  • В любом случае планировщик запросов решает выполнить сканирование по индексу is_location_independent вместо использования геоиндекса (см. обновленный вопрос). 21.01.2020
  • Сотрите частичный индекс, это была моя ошибка мышления. Да, я имею в виду два независимых индекса. Учитывая дистрибутив, следует использовать их оба. Возможно, запустить ANALYZE на столе. 21.01.2020
  • Ну, вот почему я пришел к выводу, что в первую очередь нужно добавить is_location_independent к геоиндексу, так как у меня уже были эти два отдельных индекса, и они не используются. Он делает именно то, что я разместил в разделе обновления вопроса. Сканирование самого неэффективного индекса... Странно. 22.01.2020
  • Это ИЛИ у меня есть 22.01.2020
  • Новые материалы

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

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

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

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

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

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

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