我有一些比较复杂的表格需要进行SQL查询构造/优化。目前,我们获取所需结果所使用的大部分逻辑都在应用程序层面完成,这导致了可怕的性能问题,因为需要全表遍历等操作。由于SQL不是我的强项,所以我想向SO社区寻求帮助。
基础设施背景:
- DB是MySQL5
- 我们使用Java通过Hibernate访问这些数据
- 这些表中的大多数内容都是相对静态的,除了“销售人员每小时表现”表格外,该表格包含给定销售人员活跃时间(例如,已打出或接收电话)的每个小时的一行,并显示该销售人员在整个一天内的绩效“累计”。考虑到涉及的公司销售人员数量,该表格每天可能会增加20K+行。
数据对象
我创建了一个简化版本的表格设置,其中包括相关数据。 “真正”的表格中有约20家公司,300个部门,20K名销售人员和数百万条销售人员绩效数据记录。
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);
业务需求:
- 填充一组基于Web的销售绩效“仪表板”UI,为公司、部门和个人销售人员提供单独的绩效概述。
- 这些UI在很大程度上相似,除了数据集: “公司”仪表板汇总每个公司部门所有销售人员的数据,并输出每个公司的一行;而特定公司的“部门”仪表板汇总该部门中每个销售人员的数据,并输出每个部门的一行。
这些UI允许用户选择报告仪表板的日期范围,并按任何列进行排序。显示的列包括:
(公司|部门|销售人员)名称、总下达订单数、总销售收入、总呼入电话数、总呼出电话数。
我的问题/请求:
“传统”的方法(当输出为日报时有点可耻但还算可以接受)是通过编程迭代相关对象的性能数据(例如,公司部门中的每个销售人员),找到指定日期范围内每天的“最后一个”,并对数据进行求和。然而,考虑到海量数据集以及需要在UI中“实时”呈现此数据,我需要指导/示例来构建针对此数据集的高效SQL查询,以允许分页和排序。
是否有善良的灵魂能够展示一个合理的查询,该查询获取给定日期范围内每个销售人员绩效数据列的总和(请记住,对于每一天,用于求和的行是该销售人员当天的最后一行)。
执行查询#1,涵盖一系列销售人员(例如,给定公司中的所有销售人员),并支持特定列的分页和排序的查询?
希望我已经包含了足够的细节来清楚地表明我的要求……如果您需要任何其他信息,请告诉我。
非常感谢SO SQL大神们!
更新:
从salesPerson -> division和division -> company添加了缺失的键。此外,修正了“时间戳”的数据类型为DATETIME而不是VARCHAR。