【问题标题】:Remove file sort to improve query mysql删除文件排序以改进查询 mysql
【发布时间】:2015-03-28 11:44:33
【问题描述】:

我在这个特定查询中遇到了问题,我尝试在接收表中使用索引,但它仍然使用文件排序、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$$

【问题讨论】:

    标签: mysql performance indexing filesort


    【解决方案1】:

    首先,“文件排序”只是一个问题。所以我不会专注于它。文件排序本质上是 GROUP BY 所必需的。而且并不一定意味着它接触到的磁盘。

    AND (si.dateandtime &lt;= NOW() OR h.departuredate &lt;= NOW()) 未来有条目吗?如果没有,你不能摆脱这个吗?

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

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

    这是一个“相关子查询”:( SELECT MAX(...) ... ) 它有一个覆盖索引(很好),但我们不知道它被调用的频率——可能超过 8K 次。这可能是你 7 秒的大部分时间。试着把它变成JOIN ( SELECT imei, MAX(dateandtime) FROM scanin_process_table ) foo ON ...,加上合适的行李。

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

    JOIN 和 GROUP BY 的一个普遍问题是 JOIN 扩展考虑的“行”数;然后是 GROUP BY 合同。请注意,您必须在 COUNT 中执行 DISTINCT 以避免不必要的重复。要查看这有多糟糕,请执行SELECT COUNT(*) FROM ( &lt;your SELECT, but without the GROUP BY&gt; ) 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) -- 以任意顺序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-13
      • 1970-01-01
      • 2012-03-17
      • 2014-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多