Представление разреженных записей с большим количеством столбцов в MySQL - PullRequest
0 голосов
/ 09 июля 2020

Я пытаюсь представить журнал в таблице MySQL, где каждая строка журнала содержит строку system_id, временную метку finish, 20 обязательных столбцов данных, а затем 80 дополнительных столбцов. Часто все необязательные столбцы - это нули, которые мне не обязательно хранить. Когда есть значения, это обычно только для горстки из 80 столбцов. У меня нет возможности изменить формат журнала. Я загружаю тонны этих записей, до ~ 300M сейчас.

Изначально я представил это как две таблицы ...

log_data, содержащие system_id, finish, и все обязательные столбцы с первичным ключом <system_id, finish>.

log_data_extra, содержащие system_id, finish и 80 дополнительных столбцов, первичный ключ <system_id, finish>.

Обе таблицы разделены по дате finish по месяцам. Этот путь является быстрым и легким для соединения двух таблиц, но тратит кучу дискового пространства и требует времени на вставку. Я подумал, что было бы лучше представлять только установленные значения из необязательных столбцов, а не нули. Итак, я воссоздал вторую таблицу:

Теперь log_data_extra стало system_id, finish, optional_column_number, optional_column_value с первичным ключом <system_id, finish, optional_column_number>. Это делает вставку очень быстрой, но присоединение к таблицам становится немного сложнее.

Мой запрос на соединение стал примерно таким:

select ld.system_id,
       ld.finish,
       sum((case when lde.optional_column_number = 0) then lde.optional_column_value else null end) as opt0,
       sum((case when lde.optional_column_number = 1) then lde.optional_column_value else null end) as opt1,
       sum((case when lde.optional_column_number = 2) then lde.optional_column_value else null end) as opt2,
       ... 80 times ...
  from log_data ld
  left join log_data_extra lde on ld.system_id = lde.system_id and ld.finish = lde.finish
 group by ld.system_id, ld.finish

Проблема в том, что писать запросы, которые выглядят как этот. Я планировал сделать такой запрос в представлении, log_data_with_extra, чтобы я мог присоединиться к представлению или запускать отчеты, подобные приведенным ниже:

select * from log_data_with_extra where finish between '2020-07-08' and '2020-07-09' and system_id = 'ABC123'

К сожалению, подобный запрос работает плохо. Основываясь на объяснении, похоже, что MySQL не может переместить ограничение диапазона на метку времени finish внутри группы по представлению и должен сгруппировать все столбцы (в этой таблице в настоящее время около 80 тыс. Строк) до ограничение диапазона дат. Пока я перемещаю предложение where внутри группы на MySQL, фильтрация выполняется нормально, но только не, если я пытаюсь использовать представление.

Могу ли я что-нибудь сделать, чтобы упростить эту ситуацию и сделать проще ли присоединиться ко всем 80 из этих необязательных значений в паре system_id, finish? Или мне нужно выписывать все 80 из этих фраз sum (case ()) каждый раз, когда у меня есть запрос, в котором я хочу ссылаться на них таким образом?

Спасибо!

...