Я использую 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;
Такое ощущение, что я пропускаю что-то ключевое для этого объединения / группового ... любая помощь или мысли очень ценятся!