MySQL 5.6 Вложенный GROUP BY работает в 25 раз дольше, чем запись, затем с использованием таблицы TEMPORARY - PullRequest
0 голосов
/ 02 сентября 2018

Я использую mySQL v.5.6 для сбора некоторых данных и получения сводки.

Первая таблица с ~ 500k записями:

create table panel
(
  panel_id                        char(36)    not null primary key,
  dma_id                          char(36)    null,
  dma_name                        varchar(99) null,
  geometry_lon                    float       null,
  geometry_lat                    float       null,
  air                             int         null
);

Эта таблица имеет следующие индексы:

Table  Non_unique Key_name        Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type
panel  0          PRIMARY         1            panel_id    A         446688                           BTREE
panel  1          dma_id_dma_name 1            dma_id      A         4752                        YES  BTREE
panel  1          dma_id_dma_name 2            dma_name    A         4752                        YES  BTREE

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

create table audiences
(
  panel_id                    varchar(40) null,
  daypart_id                  varchar(40) null,
  demo_id                     varchar(50) null,
  market_id                   varchar(40) null,
  total_impressions           double      null,
  total_in_market_impressions double      null,
);

Аналогично таблице панелей таблица аудиторий была проиндексирована и обращается к таблице панелей с помощью:

ALTER TABLE measures.audiences ADD PRIMARY KEY(panel_id, demo_id, market_id, daypart_id);
ALTER TABLE measures.audiences ADD CONSTRAINT FOREIGN KEY (panel_id) REFERENCES panel(panel_id);
ALTER TABLE measures.audiences ADD INDEX demo_id (demo_id);
ALTER TABLE measures.audiences ADD INDEX panel_id (panel_id);

Теперь я могу очень быстро (200 мс) присоединять выбранные аудитории к панелям даже в глобальном масштабе с помощью следующего:

  SELECT p.panel_id, p.dma_id, p.dma_name, p.geometry_lon, p.geometry_lat,
         total.total_impressions / greatest(1, air) as total,
         base.total_impressions / greatest(1, air) as base,
         target.total_impressions / greatest(1, air) as target,
         target.total_in_market_impressions / greatest(1, air) as inmarket
  FROM measures.panel p
  LEFT JOIN measures.audiences total ON total.panel_id = p.panel_id and total.demo_id = 'pf_pop'
  LEFT JOIN measures.audiences base ON base.panel_id = p.panel_id and base.demo_id = 'pf_pop_a18p'
  LEFT JOIN measures.audiences target ON target.panel_id = p.panel_id and target.demo_id = 'cb_AUTPP2U_HHLD_513ca07a4350452da3551b8f7f4b42c0'

Однако, если я попытаюсь сгруппировать и суммировать результаты, она будет выполняться более 5 минут!

SELECT dma_id as geo, dma_name as dma, avg(geometry_lon) as x, avg(geometry_lat) as y,
  sum(1) as count,
  sum(total) as total, sum(base) as base,
  sum(target) as target, sum(inMarket) as inMarket
FROM (
  SELECT p.panel_id, p.dma_id, p.dma_name, p.geometry_lon, p.geometry_lat,
         total.total_impressions / greatest(1, air) as total,
         base.total_impressions / greatest(1, air) as base,
         target.total_impressions / greatest(1, air) as target,
         target.total_in_market_impressions / greatest(1, air) as inmarket
  FROM measures.panel p
  LEFT JOIN measures.audiences total ON total.panel_id = p.panel_id and total.demo_id = 'pf_pop'
  LEFT JOIN measures.audiences base ON base.panel_id = p.panel_id and base.demo_id = 'pf_pop_a18p'
  LEFT JOIN measures.audiences target ON target.panel_id = p.panel_id and target.demo_id = 'cb_AUTPP2U_HHLD_513ca07a4350452da3551b8f7f4b42c0'
) g
GROUP BY dma_id, dma_name;

ОБЪЯСНЕНИЕ в списках длинных запросов Extra: Using temporary; Using filesort.

Странным битом всего этого является то, что если я создаю временную таблицу, а затем на отдельном шаге выполняю GROUP BY, она выполняется только за 14сек ... все еще долго, но ОГРОМНО 25-кратное улучшение по сравнению с вложенным 5-минутным запросом .

DROP TEMPORARY TABLE IF EXISTS temp;

CREATE TEMPORARY TABLE temp (INDEX (dma_id, dma_name)) as
  SELECT p.panel_id, p.dma_id, p.dma_name, p.geometry_lon, p.geometry_lat,
     total.total_impressions / greatest(1, air) as total,
     base.total_impressions / greatest(1, air) as base,
     target.total_impressions / greatest(1, air) as target,
     target.total_in_market_impressions / greatest(1, air) as inmarket
  FROM measures.panel p
  LEFT JOIN measures.audiences total ON total.panel_id = p.panel_id and total.demo_id = 'pf_pop'
  LEFT JOIN measures.audiences base ON base.panel_id = p.panel_id and base.demo_id = 'pf_pop_a18p'
  LEFT JOIN measures.audiences target ON target.panel_id = p.panel_id and target.demo_id = 'cb_AUTPP2U_HHLD_ff727e884402f4a25cfa0a66f182ed1e';

SELECT dma_id as geo, dma_name as dma, avg(geometry_lon) as x, avg(geometry_lat) as y,
  sum(1) as count,
  sum(total) as total, sum(base) as base,
  sum(target) as target, sum(inMarket) as inMarket
FROM temp
GROUP BY dma_id, dma_name;

НО, конечно, было бы неплохо приблизиться к времени, затрачиваемому на GROUP BY, только за столом панели (143 мс) , где EXPLAIN перечисляет только { type: index, key: dma_id_dma_name }

SELECT dma_id as geo, dma_name as dma, avg(geometry_lon) as x, avg(geometry_lat) as y,
  sum(1) as count
FROM measures.panel
GROUP BY dma_id, dma_name;

Такое ощущение, что я пропускаю что-то ключевое для этого объединения / группового ... любая помощь или мысли очень ценятся!

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