CASE запрос оптимизации - PullRequest
0 голосов
/ 19 февраля 2020
SELECT
  COUNT(CASE WHEN VALUE = 1 THEN 1 END) AS score_1,
  COUNT(CASE WHEN VALUE = 2 THEN 1 END) AS score_2,
  COUNT(CASE WHEN VALUE = 3 THEN 1 END) AS score_3,
  COUNT(CASE WHEN VALUE = 4 THEN 1 END) AS score_4,
  COUNT(CASE WHEN VALUE = 5 THEN 1 END) AS score_5,
  COUNT(CASE WHEN VALUE = 6 THEN 1 END) AS score_6,
  COUNT(CASE WHEN VALUE = 7 THEN 1 END) AS score_7,
  COUNT(CASE WHEN VALUE = 8 THEN 1 END) AS score_8,
  COUNT(CASE WHEN VALUE = 9 THEN 1 END) AS score_9,
  COUNT(CASE WHEN VALUE = 10 THEN 1 END) AS score_10
FROM
  `answers`
WHERE
`created_at` BETWEEN '2017-01-01 00:00:00' AND '2019-11-30 23:59:59' 

Есть ли способ оптимизировать этот запрос, потому что у меня есть 4 миллиона записей ответов в моей БД, и он работает очень медленно?

Ответы [ 3 ]

0 голосов
/ 19 февраля 2020

Вы можете попробовать добавить избыточный составной индекс

create idx1 on table answers(created_at, value)

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

0 голосов
/ 19 февраля 2020

Хотите, чтобы это было в 10 раз быстрее? Используйте технику хранилища данных для построения и ведения «Сводной таблицы». В этом примере сводная таблица может быть

CREATE TABLE subtotals (
    dy DATE NOT NULL,
    `value` ... NOT NULL,   -- TINYINT UNSIGNED ?
    ct SMALLINT UNSIGNED NOT NULL, -- this is 2 bytes, max 65K; change if might be bigger
    PRIMARY KEY(value, dy)  -- or perhaps the opposite order
) ENGINE=InnoDB

Каждую ночь вы суммируете данные дня и строите 10 новых строк в subtotals.

Тогда запрос «report» становится

SELECT
  SUM(CASE WHEN VALUE = 1 THEN ct END) AS score_1,
  SUM(CASE WHEN VALUE = 2 THEN ct END) AS score_2,
  SUM(CASE WHEN VALUE = 3 THEN ct END) AS score_3,
  SUM(CASE WHEN VALUE = 4 THEN ct END) AS score_4,
  SUM(CASE WHEN VALUE = 5 THEN ct END) AS score_5,
  SUM(CASE WHEN VALUE = 6 THEN ct END) AS score_6,
  SUM(CASE WHEN VALUE = 7 THEN ct END) AS score_7,
  SUM(CASE WHEN VALUE = 8 THEN ct END) AS score_8,
  SUM(CASE WHEN VALUE = 9 THEN ct END) AS score_9,
  SUM(CASE WHEN VALUE = 10 THEN ct END) AS score_10
FROM
  `subtotals`
WHERE `created_at` >= '2017-01-01'
  AND `created_at`  < '2019-12-01'

Исходя из того, что вы предоставили, в subtotals будет около 10 тыс. Строк; это намного меньше, чем 4 миллиона строк. Он может работать более чем в 10 раз быстрее.

Дополнительные обсуждения: http://mysql.rjweb.org/doc.php/summarytables

0 голосов
/ 19 февраля 2020

Попробуйте выполнить это один раз, чтобы создать индекс:

CREATE INDEX ix_ca on answers(created_at)

Это должно ускорить ваш запрос. Если вам интересно, почему, смотрите здесь:

Что такое индекс в SQL?

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