在具有数百万个记录表的复合键上加入子查询

时间:2013-12-13 01:19:18

标签: mysql sql optimization mysql-5.6

我有一些非常大的桌子 - 一个是大约200,000,000(扫描),另一个是大约50,000,000(片断细节)。它们通常连接在一组匹配的列上 - 特别是USPS条形码数据(zip,zip_4,zip_delivery_point,serial_number)。由于它通常是定位匹配扫描的片段详细记录,因此我想通过查找条件对扫描记录进行分区(片段详细记录由表示邮件的不同密钥集分区)。这使我从自动增量PK转变为zip,zip_4,zip_delivery_point,serial_number,scan_date_time的组合。

我现在遇到的问题是优化我的一些大型报告查询。我经常运行一些脚本来处理数据,包括查找每个邮件的第一个扫描日期,每个邮件的最新扫描日期,计算交付日期等。我经常发现自己需要执行这样的连接:

SELECT a, b, c, s1.first, s2.latest
FROM (subquery to grab MIN() scan record) s1
JOIN _scan s2 ON some_id = (subquery to grab MAX() scan record using fields from s1)

由于我的PK没有一个好的单一col,我无法以这种方式对记录执行连接,除非我将动态或前期的复合键值连接到假的a单列密钥。但这似乎是多余的。

维护按当前复合键排序的记录的物理顺序是什么好方法,同时还能够加入可以利用先前子查询的子查询的结果(在我的示例中为s1和s2) )吗

注意:我现在可以通过用子查询替换连接表然后加入该别名来实现正确的结果,但是mysql似乎希望在以这种方式执行连接之前将整个表加载到内存中。

表结构

CREATE TABLE `_scan` (
  `facility_zip` varchar(5) NOT NULL,
  `operation_code` varchar(3) NOT NULL,
  `scan_date_time` datetime NOT NULL,
  `zip` varchar(5) NOT NULL DEFAULT '',
  `zip_4` varchar(4) NOT NULL,
  `zip_delivery_point` varchar(2) NOT NULL,
  `barcode_identifier` varchar(2) NOT NULL,
  `service_type` varchar(3) NOT NULL,
  `mailer_id` varchar(9) NOT NULL,
  `serial_number` varchar(9) NOT NULL,
  `new` tinyint(1) NOT NULL DEFAULT '1',
  `first_scan` tinyint(1) DEFAULT NULL,
  PRIMARY KEY (`zip`,`zip_4`,`zip_delivery_point`,`serial_number`,`scan_date_time`),
  KEY `operation_code` (`operation_code`)
) ENGINE=InnoDB
/*!50100 PARTITION BY KEY (zip,zip_4,zip_delivery_point,serial_number,scan_date_time)
PARTITIONS 10 */;

CREATE TABLE `_piece_detail` (
  `job_id` varchar(8) NOT NULL,
  `piece_id` bigint(20) NOT NULL,
  `cqt_database_id` int(11) NOT NULL,
  `package_id` int(11) NOT NULL,
  `barcode_identifier` int(11) DEFAULT NULL,
  `service_type` int(11) DEFAULT NULL,
  `mailer_id` varchar(9) DEFAULT NULL,
  `serial_number` varchar(9) NOT NULL,
  `zip` varchar(5) NOT NULL,
  `zip_4` varchar(4) NOT NULL,
  `zip_delivery_point` varchar(2) NOT NULL,
  `est_delivery_date` date DEFAULT NULL,
  `first_scan_date_time` datetime DEFAULT NULL,
  `latest_scan_date_time` datetime DEFAULT NULL,
  PRIMARY KEY (`job_id`,`piece_id`),
  KEY `cqt_database_id` (`cqt_database_id`) USING BTREE,
  KEY `est_delivery_date` (`est_delivery_date`),
  KEY `zip` (`zip`,`zip_4`,`zip_delivery_point`,`serial_number`),
  KEY `first_scan_date_time` (`first_scan_date_time`),
  KEY `latest_scan_date_time` (`latest_scan_date_time`)
) ENGINE=InnoDB
/*!50100 PARTITION BY KEY (job_id,piece_id)
PARTITIONS 10 */;

0 个答案:

没有答案