psql запрос CASE против множественного выбора для больших наборов данных - производительность - PullRequest
0 голосов
/ 14 мая 2018

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

ПРИМЕР КЕЙСА:

SELECT SUM(CASE WHEN(created_at > (CURRENT_DATE - INTERVAL '1 days')) THEN 1 ELSE 0 END) as day_count,
SUM(CASE WHEN(created_at > (CURRENT_DATE - INTERVAL '1 months')) THEN 1 ELSE 0 END) as month_count,
SUM(CASE WHEN(created_at > (CURRENT_DATE - INTERVAL '3 months')) THEN 1 ELSE 0 END) as quater_count,
SUM(CASE WHEN(created_at > (CURRENT_DATE - INTERVAL '6 months')) THEN 1 ELSE 0 END) as half_year_count,
SUM(CASE WHEN(created_at > (CURRENT_DATE - INTERVAL '1 years')) THEN 1 ELSE 0 END) as year_count,
count(*) as total_count from wallets;

Запрос множественного выбора:

SELECT count(*) from wallets where created_at > CURRENT_DATE - INTERVAL '1 days';
SELECT count(*) from wallets where created_at > CURRENT_DATE - INTERVAL '1 months';
SELECT count(*) from wallets where created_at > CURRENT_DATE - INTERVAL '3 months';
SELECT count(*) from wallets where created_at > CURRENT_DATE - INTERVAL '6 months';
SELECT count(*) from wallets where created_at > CURRENT_DATE - INTERVAL '1 years';
SELECT count(*) from wallets;

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

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

Пожалуйста, найдите анализ запросов ниже, у меня есть только 10 записей в моей БД:

Анализ запросов случая:

enter image description here

Анализ нескольких запросов:

enter image description here

Ответы [ 3 ]

0 голосов
/ 14 мая 2018

Я могу сделать обоснованное предположение. Без реальных данных тесты малопригодны.

Запрос множественного выбора легче оптимизировать с помощью плоской базы данных. Для этого PostgreSQL 9.6+ может использовать index, сканирует только . Это может закончиться несколькими очень быстрыми запросами.

Пример Case очень трудно читать. Боюсь, никто не может написать индекс для этого, и запрос будет вынужден сканировать всю таблицу. Это может быть ужасно медленная операция.

0 голосов
/ 14 мая 2018

Один запрос будет лучше.Вы получите улучшение производительности, используя filter:

SELECT COUNT(*) FILTER (WHERE created_at > (CURRENT_DATE - INTERVAL '1 days')) as day_count,
       COUNT(*) FILTER (WHERE created_at > (CURRENT_DATE - INTERVAL '1 months'))  as month_count,
       COUNT(*) FILTER (WHERE created_at > (CURRENT_DATE - INTERVAL '3 months')) as quater_count,
       COUNT(*) FILTER (WHERE created_at > (CURRENT_DATE - INTERVAL '6 months')) as half_year_count,
       COUNT(*) FILTER (WHERE created_at > (CURRENT_DATE - INTERVAL '1 years')) as year_count,
       COUNT(*) as total_count 
FROM wallets;

Если у вас есть индекс на created_at, то это также должно помочь Postgres оптимизировать использование только этого индекса.

0 голосов
/ 14 мая 2018

С точки зрения knex, разница в том, что несколько запросов могут быть отправлены в БД через отдельные соединения и выполнены параллельно. Выполнение всего лишь одного запроса, вероятно, в целом более производительно, что приводит к меньшим нагрузкам и нагрузкам на передачу данных на сервер БД.

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

Лучший способ добиться такого типа упаковки нескольких запросов в один - использовать оператор postgres with (общие табличные выражения) https://www.postgresql.org/docs/9.6/static/queries-with.html, который knexalso поддерживает http://knexjs.org/#Builder-with

РЕДАКТИРОВАТЬ: или просто выполнить несколько запросов в одном выделении, как советует Гордон Линофф:

knex
  .select( 
    knex('wallets')
      .where('createad_at', '>', knex.raw("CURRENT_DATE - INTERVAL '1 days'"))
      .count()
      .as('lastDay'),
    knex('wallets')
      .where('createad_at', '>', knex.raw("CURRENT_DATE - INTERVAL '1 months'"))
      .count()
      .as('lastMonth'),
      ... rest of the queries ...
  );

https://runkit.com/embed/wsy01ar1hb73

postgresql должен иметь возможность оптимизировать несколько подзапросов, которые будут выполняться с помощью плана similair, который предлагает ответ Гордона.

...