LEFT-JOIN和Group By的Mysql性能问题

时间:2015-01-09 11:45:59

标签: mysql performance optimization group-by left-join

我有2张桌子EMP& EMP_DTL。我正在使用LEFT JOIN,如下所示。

SELECT EMPDEL, 
    EMPYEAR, 
    EXCODE, 
    CONCAT(COALESCE(TCODE, ''), COALESCE(INTCODE, '')) AS INTCODE, 
    (   SELECT GROUP_CONCAT(ECODE SEPARATOR ' ') FROM EMP_DTL 
        WHERE EMP_DTL.DTL_EID = EMP.EID AND ETYPE='')  AS ECODE, 
    COUNT(SSN)                                         AS SSN,
    MIN(ESRP)                                          AS ESRP, 
    GROUP_CONCAT(DISTINCT CURCODE SEPARATOR ' ')       AS CURCODE 
 FROM EMP 
 WHERE EAND='TOY' 
    AND EMPYEAR IN ('2014', '2015') 
    AND EGORY IN('G') 
    AND (EHIND = 'N' OR EHIND = 'FALSE') 
    AND EMP.SSN IS NOT NULL 
    AND ESRP > 0 
 GROUP BY EMPDEL, EMPYEAR, EXCODE, INTCODE, ECODE

并且表结构是这样的,

CREATE TABLE `emp` (
  `EID` varchar(45) NOT NULL,
  `ETYPE` varchar(1) NOT NULL,
  `SSN` varchar(20) DEFAULT NULL,
  `EMPDEL` varchar(4) DEFAULT NULL,
  `EMPYEAR` varchar(4) DEFAULT NULL,
  `ESCODE` varchar(2) DEFAULT NULL,
  `EIAL` varchar(45) DEFAULT NULL,
  `EAND` varchar(20) DEFAULT NULL,
  `ETUS` char(2) DEFAULT NULL,
  `ESRP` varchar(20) DEFAULT NULL,
  `EHIND` varchar(20) DEFAULT NULL,
  `EGORY` char(1) DEFAULT NULL,
  `ECODE` varchar(200) DEFAULT NULL,
  `EXCODE` varchar(10) DEFAULT NULL,
  `TCODE` varchar(5) DEFAULT NULL,
  `INTCODE` varchar(20) DEFAULT NULL,
  `CURCODE` varchar(10) DEFAULT NULL,
  `EAREA` varchar(5) DEFAULT NULL,
  PRIMARY KEY (`EID`),
  UNIQUE KEY `EID` (`EID`),
  KEY `SSN_IDX` (`SSN`),
  KEY `EMPDEL_IDX` (`EMPDEL`),
  KEY `EMPYEAR_IDX` (`EMPYEAR`),
  KEY `EAREA_IDX` (`EAREA`),
  KEY `ETUS_IDX` (`ETUS`),
  KEY `EAND_IDX` (`EAND`),
  KEY `ESRP_IDX` (`ESRP`),
  KEY `EHIND_IDX` (`EHIND`),
  KEY `EGORY_IDX` (`EGORY`)
) 

CREATE TABLE `emp_dtl` (
  `DTL_EID` varchar(45) NOT NULL,
  `SSN` varchar(20) DEFAULT NULL,
  `ECODE` varchar(45) NOT NULL,
  `ETYPE` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`DTL_EID`,`ECODE`),
  KEY `EMP_DTL_IDX` (`DTL_EID`),
  KEY `ETYPE_IDX` (`ETYPE`)
) 

问题是查询正在执行10000个记录大约30秒。

我尝试在上面的查询中添加这些内容以提高性能,

1)添加" WHERE"条款

2)在两个表中为WHERE子句中的id和列添加了适当的索引。

3)执行执行计划以确保使用我的索引。这是执行计划的输出。

ID   SELECT_TYPE             TABLE      TYPE   POSSIBLE_KEYS                                                KEY                     KEY_LEN     REF      ROWS   EXTRA
=====================================================================================================================================================================================
'1', 'PRIMARY',             'EMP',     'ref', 'SSN_IDX,EMPYEAR_IDX,EAND_IDX,ESRP_IDX,EHIND_IDX, EGORY_IDX', 'EGORY_IDX',            '2',        'const', '13',  'Using where; Using filesort'
'2', 'DEPENDENT  SUBQUERY', 'EMP_DTL', 'ref', 'PRIMARY,EMP_DTL_IDX,ETYPE_IDX',                              'ETYPE_IDX',            '48',       'const', '1',   'Using where; Using index'

我应该再添加一个索引吗? 有人可以帮助我进一步优化这个查询以减少执行时间吗?

2 个答案:

答案 0 :(得分:0)

问题是您实际上没有加入,而是在EMP_DTL中为每个EMP记录开始单独查找。试试这个:

SELECT EMP.EMPDEL, 
    EMP.EMPYEAR, 
    EMP.EXCODE, 
    CONCAT(COALESCE(TCODE, ''), COALESCE(INTCODE, '')) AS INTCODE, 
    GROUP_CONCAT(EMP_DTL.ECODE SEPARATOR ' ')          AS ECODE, 
    EMP.COUNT(SSN)                                     AS SSN,
    MIN(EMP.ESRP)                                      AS ESRP, 
    EMP.GROUP_CONCAT(DISTINCT CURCODE SEPARATOR ' ')   AS CURCODE 
 FROM EMP 
 LEFT JOIN EMP_DTL ON EMP_DTL.DTL_EID = EMP.EID AND EMP_DTL.ETYPE=''
 WHERE EAND='TOY' 
    AND EMPYEAR IN ('2014', '2015') 
    AND EGORY IN('G') 
    AND (EHIND = 'N' OR EHIND = 'FALSE') 
    AND EMP.SSN IS NOT NULL 
    AND ESRP > 0 
 GROUP BY EMPDEL, EMPYEAR, EXCODE, INTCODE, ECODE

答案 1 :(得分:0)

除了来自Dirk的左连接产品之外,您在不同的字段上有单独的索引,这对多键索引没有多大帮助。尝试在表上放置索引以覆盖WHERE子句的主要元素和组的元素...但是有这么多列可能太多而且不实用。仅在WHERE子句键上设置结果可能足以提高性能。

在...上创建索引(EGORY,EAND,EMPYEAR,EHIND,SSN,ESRP)