Почему использование функции MAX в запросе вызывает проблему производительности postgresql? - PullRequest
0 голосов
/ 15 апреля 2020

У меня есть таблица с тремя столбцами time_stamp, device_id и status st status, тип json. Также столбцы time_stamp и device_id имеют index . Мне нужно получить последнее значение статуса с идентификатором 1.3.6.1.4.1.34094.1.1.1.1.1, который не является нулевым.

Вы можете найти время выполнения запроса следующей команды С и Без , используя MAX ниже.

Запрос с MAX:

SELECT DISTINCT MAX(time_stamp) FROM device.status_events WHERE 
(device_id = 7) AND
   (status->'1.3.6.1.4.1.34094.1.1.1.1.1' != '{}');

query with MAX

Запрос без MAX:

SELECT DISTINCT time_stamp FROM device.status_events WHERE 
(device_id = 7) AND
   (status->'1.3.6.1.4.1.34094.1.1.1.1.1' != '{}');

query without MAX

Первый запрос занимает около 3se c, а второй занимает всего 3mse c с два разных плана. Я думаю, что оба запроса должны иметь один и тот же план запросов. Почему он не использует index , когда он хочет вычислить MAX? Как можно улучшить время выполнения первого запроса?

PS Я использую postgres 9.6 (версия для Docker).

Также это определение таблицы.

-- Table: device.status_events

-- DROP TABLE device.status_events;

CREATE TABLE device.status_events
(
  time_stamp timestamp with time zone NOT NULL,
  device_id bigint,
  status jsonb,
  is_active boolean DEFAULT true,
  CONSTRAINT status_events_device_id_fkey FOREIGN KEY (device_id)
      REFERENCES device.devices (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE
)
WITH (
  OIDS=FALSE
);
ALTER TABLE device.status_events
  OWNER TO monitoring;

-- Index: device.status_events__time_stamp

-- DROP INDEX device.status_events__time_stamp;

CREATE INDEX status_events__time_stamp
  ON device.status_events
  USING btree
  (time_stamp);

Ответы [ 2 ]

1 голос
/ 18 апреля 2020

Указанный вами индекс не может дать первый план, который вы нам показываете. С этим индексом план должен будет применить фильтр для столбца jsonb, а это не так. Таким образом, индекс должен быть частичным, с фильтром, применяемым на уровне индекса, чтобы он не требовался в плане.

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

Все ваши devide_id = 7 должны иметь низкие метки времени, но PostgreSQL не знает этого. Он думает, что, пройдя по индексу меток времени, он быстро найдет device_id = 7, а затем будет готово. Но вместо этого ему нужно пройти большой кусок индекса, прежде чем найти такую ​​строку.

Вы можете принудительно удалить его из «неправильного» индекса, изменив агрегатное выражение на что-то вроде:

MAX(time_stamp + interval '0')

Или вместо этого вы можете создать более специализированный индекс, который планировщик выберет вместо ложно привлекательного:

create index on device.status_events (device_id , time_stamp) 
    where status->'1.3.6.1.4.1.34094.1.1.1.1.1' != '{}';
0 голосов
/ 15 апреля 2020

Я считаю, что это должно создать лучший план

SELECT time_stamp FROM device.status_events WHERE 
(device_id = 7) AND
   (status->'1.3.6.1.4.1.34094.1.1.1.1.1' != '{}')
ORDER BY timestamp DESC
LIMIT 1

Дайте мне знать, как это работает для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...