删除文件排序以改进查询mysql

时间:2015-01-29 09:48:50

标签: mysql performance indexing filesort

我在这个特定的查询中有一个问题,我尝试在receiving_table中使用索引,但它仍然使用filesort,Mysql,数据库一般,不是我的强项,我还在学习基础知识,我只有8000条记录和7秒的查询很慢,我附上了我的查询和数据库,对不起英语也不是我的强项,提前谢谢

1	PRIMARY	re	index	PRIMARY,imei_index,imeibatchclientyear,batches	batches	20		8326	Using index; Using temporary; Using filesort
1	PRIMARY	b	ref	PRIMARY,batch	PRIMARY	26	tracking_system_1_schema.re.clientcode,tracking_system_1_schema.re.batchnum	1	Using where
1	PRIMARY	hh	eq_ref	PRIMARY	PRIMARY	24	tracking_system_1_schema.re.imei	1	Using where; Using index
1	PRIMARY	rm	eq_ref	PRIMARY	PRIMARY	24	tracking_system_1_schema.re.imei	1	Using where
1	PRIMARY	si	ref	PRIMARY,imei,date	date	22	func,tracking_system_1_schema.re.imei	1	Using where; Using index
1	PRIMARY	h	ref	imei_index	imei_index	30	tracking_system_1_schema.b.clientcode,tracking_system_1_schema.re.batchnum,tracking_system_1_schema.re.year	136	Using where
2	DEPENDENT SUBQUERY	ssi	ref	PRIMARY,imei	imei	17	tracking_system_1_schema.re.imei	2	Using index

EXPLAIN
SELECT	   
	b.clientcode  AS 'CUSTOMER',	
	b.batchnum  AS 'BATCH NUMBER',
	b.year,
	b.datereceived AS 'DATE RECEIVED',
	b.quantity AS 'BATCH QTY' , 
	COUNT(DISTINCT  re.imei ) + COUNT(DISTINCT IFNULL(h.imei, NULL) )  AS 'RECEIVE ITEMS',
	COUNT(DISTINCT IFNULL(h.imei , NULL)) AS 'SHIPPED ITEMS',	
	COUNT(DISTINCT  re.imei  ) - COUNT(DISTINCT IF(si.processcode = 51, si.imei  , NULL))   - COUNT(DISTINCT IF((hh.imei = si.imei OR rm.imei= si.imei) AND si.processcode != 51 , si.imei , NULL))  AS 'WIP',
	COUNT(DISTINCT IF(si.processcode = 51, si.imei 	 , NULL))  - COUNT(DISTINCT IF((hh.imei = si.imei OR rm.imei= si.imei) AND si.processcode = 51 , si.imei , NULL))   AS 'FGS',
	COUNT(DISTINCT hh.imei) + COUNT(DISTINCT  rm.imei) AS 'HOLD ITEMS'
FROM	
	tracking_system_1_schema.scanin_process_table si	
INNER JOIN
	tracking_system_1_schema.receiving_table re 
ON 
	re.imei = si.imei
LEFT OUTER JOIN
	tracking_system_1_schema.hold_table hh 
ON
	hh.imei = re.imei  
LEFT OUTER JOIN
	tracking_system_1_schema.rma_status_Table rm
ON
	re.imei = rm.imei
AND
	rm.status = 2
INNER JOIN
	tracking_system_1_schema.batch_table b
ON
	b.batchnum = re.batchnum 
AND
	b.clientcode = re.clientcode
AND
	b.year = re.year
LEFT OUTER JOIN
	item_history_1_schema.item_history_table  h
ON
	b.batchnum = h.batchnum
AND
	b.clientcode = h.clientcode  
AND
	b.year = h.year
WHERE  
	si.dateandtime = 
	(
		SELECT	
			MAX(ssi.dateandtime)
		FROM
			tracking_system_1_schema.scanin_process_table ssi
		WHERE
			ssi.imei = re.imei
	)
AND
	(si.dateandtime <= NOW()
OR
	h.departuredate <= NOW()) 
GROUP BY
	re.clientcode,
	re.batchnum ,
	re.year
;

delimiter $$

CREATE TABLE `receiving_table` (
  `imei` varchar(15) NOT NULL,
  `modelname` varchar(20) NOT NULL,
  `batchnum` int(10) NOT NULL,
  `clientcode` varchar(10) NOT NULL,
  `dateandtime` datetime NOT NULL,
  `status` int(11) NOT NULL DEFAULT '0',
  `workerid` varchar(6) NOT NULL,
  `reusecount` bigint(20) NOT NULL,
  `gradebatch` varchar(30) NOT NULL,
  `serialnum` varchar(15) NOT NULL,
  `modifydate` datetime DEFAULT NULL,
  `simcarrier` varchar(20) DEFAULT NULL,
  `ismanual` int(1) DEFAULT '0',
  `modelnumber` varchar(15) DEFAULT NULL,
  `fccid` varchar(15) DEFAULT NULL,
  `rmastatus` int(11) DEFAULT '0',
  `simtraystatus` varchar(15) DEFAULT 'null',
  `batchtype` int(2) DEFAULT '0',
  `withlcmmarking` bit(1) NOT NULL DEFAULT b'0',
  `year` int(10) NOT NULL DEFAULT '2015',
  PRIMARY KEY (`imei`),
  UNIQUE KEY `imei_index` (`imei`) USING BTREE,
  KEY `imeibatchclientyear` (`imei`,`clientcode`,`batchnum`,`year`),
  KEY `batches` (`batchnum`,`clientcode`,`year`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$

1 个答案:

答案 0 :(得分:0)

首先,&#34; filesort&#34;只是一个问题。所以我不会专注于它。 GROUP BY基本上需要filesort。它并不一定意味着它触及的磁盘。

AND (si.dateandtime <= NOW() OR h.departuredate <= NOW()) 将来会有参赛作品吗?如果没有,你不能摆脱这个吗?

如果确实需要,请尝试将语句转换为UNION DISTINCT。这将为优化器提供使用包含其中一列的索引的机会。

COUNT(DISTINCT)需要在UNION之外。也就是说,UNION需要在子查询中。

这是一个&#34;相关的子查询&#34;:( SELECT MAX(...) ... )它有一个覆盖索引(好),但我们不知道它被调用的频率 - 可能超过8K次。这个可能是你7秒钟的大部分时间。尝试将其转换为JOIN ( SELECT imei, MAX(dateandtime) FROM scanin_process_table ) foo ON ...,加上合适的行李。

请注意,使JOIN成为要处理的第一个表。所以,你需要INDEX(imei, dateandtime)。 (我在这里的细节很模糊。)

JOIN和GROUP BY的一个普遍问题是JOIN 扩展&#34;行的数量&#34;在考虑中;那么GROUP BY 合同。请注意,您必须在COUNT中执行DISTINCT以避免不必要的重复。要查看这有多糟糕,请SELECT COUNT(*) FROM ( <your SELECT, but without the GROUP BY> ) x;我猜它可能超过一百万。这也可能是7秒的原因。

因此,一般的解决方案是明智地将查询拆分为带有子查询的查询。唉,我看不出容易分手了。以下是部分解决方案:将b拆分为外部查询。请注意b的字段在任何地方都没有真正使用过。 (h可以从re而不是b获得。)通过拉出b.clientcode等,tmp表不必将它们拉到周围。 (因此,百万行tmp表会更小,因此速度更快。但速度不是很快。)

您可以通过简单地删除对b的所有引用来试验拆分b。然后看看它的运行速度。然后(如果它明显更快),那么使用它:

SELECT b.clientcode ...
    FROM ( <all the rest> ) x
    JOIN tracking_system_1_schema.batch_table b ON b.year = x.year AND ...;

确保b具有INDEX(batchnum, clientcode, year) - 任何顺序。