У меня есть несколько сложный ассортимент таблиц, для которых мне нужно сделать конструкцию / оптимизацию SQL-запроса. В настоящее время большая часть логики, используемой для получения необходимых нам результатов, выполняется на уровне приложения, что приводит к ужасной производительности из-за полных обходов таблиц и т. Д. SQL не является моей сильной стороной, поэтому я решил, что достигну чтобы увидеть толпу, чтобы кто-нибудь мог протянуть руку.
Инфраструктура Фон:
- БД - MySQL5
- Мы получаем доступ к этим данным через Hibernate, используя Java
- Большинство этих таблиц относительно статичны, за исключением таблицы «salesperson-hourly-performance», которая содержит строку для каждого часа каждого дня, в течение которого данный продавец является активным (например, совершил или получил вызов ) с подсчетом производительности этого продавца за весь день. Учитывая количество продавцов в рассматриваемых компаниях, эта таблица может расти на 20 000+ строк в день.
Объекты данных
Я создал упрощенную версию настройки таблицы, которая включает в себя соответствующие данные. В «настоящих» таблицах содержится около 20 компаний, 300 отделов, 20 000 продавцов и миллионы записей данных о производительности продавцов.
CREATE TABLE `so_test`.`company` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1;
INSERT INTO company VALUES (7, 'CompanyXX');
CREATE TABLE `so_test`.`division` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(45) NOT NULL,
`campanyId` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=latin1;
INSERT INTO division VALUES (17, 'APAC #1');
CREATE TABLE `so_test`.`salesperson` (
`id` int(10) unsigned NOT NULL auto_increment,
`divisionId` int(10) unsigned NOT NULL,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=213860 DEFAULT CHARSET=latin1;
INSERT INTO salesperson VALUES (213859, 'bob jones');
CREATE TABLE `so_test`.`salesperson_hourly_performance` (
`id` int(10) unsigned NOT NULL auto_increment,
`timestamp` DATETIME NOT NULL,
`salesPersonId` int(10) unsigned NOT NULL,
`callsInBound` int(10) unsigned NOT NULL,
`callsOutBound` int(10) unsigned NOT NULL,
`issuedOrders` int(10) unsigned NOT NULL,
`salesRevenue` decimal(10,4) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=552395 DEFAULT CHARSET=latin1;
INSERT INTO salesperson_hourly_performance VALUES (552394, '2009-05-03 22:00:00', 213859, 15, 17, 14, 10798.0478),
(551254, '2009-05-03 21:00:00', 213859, 14, 16, 13, 9802.3620),
(551115, '2009-05-03 20:00:00', 213859, 13, 14, 12, 9183.8250),
(550072, '2009-05-03 19:00:00', 213859, 11, 13, 11, 8490.8678),
(549613, '2009-05-03 18:00:00', 213859, 10, 11, 9, 7230.1125),
(549389, '2009-05-03 17:00:00', 213859, 9, 10, 8, 6486.2173),
(548861, '2009-05-03 16:00:00', 213859, 7, 9, 7, 5537.8553),
(548059, '2009-05-03 15:00:00', 213859, 6, 8, 6, 4663.8469),
(547466, '2009-05-03 14:00:00', 213859, 5, 7, 5, 4082.6388),
(546729, '2009-05-03 13:00:00', 213859, 4, 6, 4, 3057.7368),
(546611, '2009-05-03 12:00:00', 213859, 3, 5, 2, 1751.6135),
(545642, '2009-05-03 11:00:00', 213859, 2, 4, 2, 1751.6135),
(545558, '2009-05-03 10:00:00', 213859, 1, 3, 0, 0.0000),
(545072, '2009-05-03 09:00:00', 213859, 1, 2, 0, 0.0000),
(565071, '2009-05-04 13:00:00', 213859, 19, 17, 6, 4200.1710),
(575070, '2009-05-06 14:00:00', 213859, 0, 2, 1, 120.0000);
Бизнес-требования:
- Заполните набор веб-интерфейсов «панели мониторинга» эффективности продаж, которые предоставляют отдельный обзор производительности для компаний, подразделений и отдельных специалистов по продажам.
- Интерфейсы пользователя в значительной степени похожи друг на друга, за исключением набора данных: панель мониторинга «company» объединяет все данные всех продавцов в каждом из подразделений компании и выводит по одной строке для каждой компании, тогда как панель мониторинга для подразделения конкретная компания агрегирует данные о каждом из продавцов в этом отделе и по строке на подразделение.
Интерфейсы позволяют пользователю выбирать диапазон дат для панели мониторинга отчета и сортировать по любому из столбцов. Отображаемые столбцы:
(Company | Division | Sales Person) Имя, Всего выпущенных заказов, Общий доход от продаж, Общее количество входящих вызовов, Общее количество исходящих вызовов.
Моя проблема / просьба к SO:
«Унаследованный» подход (который был позорным, но в некотором смысле довольно приемлемым, когда выходной был для ежедневного журнала) заключался в программной итерации данных о производительности для каждого из соответствующих объектов (например, каждого продавца в подразделение в компании), найдите «последний» в каждый из указанных дней в указанном диапазоне дат и суммируйте данные. Однако, учитывая массивный набор данных и необходимость представления этих данных «вживую» в пользовательском интерфейсе, мне нужны рекомендации / примеры того, как построить эффективные запросы SQL к этому набору данных, которые позволят разбивать на страницы и сортировать.
Может, какая-нибудь добрая душа покажет мне разумный запрос, который получает сумму каждого из столбцов данных о производительности торгового представителя для данного диапазона дат (учитывая, что для каждого дня строка, используемая для суммы последний по дате для этого дня, для этого продавца).
Запрос, который выполняет запрос № 1 для ряда продавцов (например, для всех продавцов в данной компании) с поддержкой нумерации страниц и заказов в определенном столбце?
Надеюсь, я включил достаточно подробностей, чтобы уточнить, о чем я спрашиваю ... пожалуйста, дайте мне знать, если вам нужна дополнительная информация.
Большое спасибо ТАК Боги SQL!
UPDATE:
Добавлены недостающие ключи от SalesPerson -> Division & from Division -> company. Также исправлен тип данных «timestamp», который будет DATETIME вместо VARCHAR.