如何使用DISTINCT推送查询?

时间:2018-03-22 08:07:04

标签: mysql query-optimization distinct

最初我有以下查询:

SELECT 
  rm.`routeNumber`
FROM
  transactions tr 
  LEFT OUTER JOIN route_map rm 
    ON rm.`idStation` = tr.`idStation` 
    AND rm.`routeNumber` = CONCAT(
      tr.`routeNumber`,
      IF(
        tr.`letterOfRoute` REGEXP '[0-9]+' 
        OR tr.`letterOfRoute` IS NULL,
        '',
        tr.`letterOfRoute`
      )
    ) 
  LEFT OUTER JOIN station s 
    ON s.idStation = rm.`idStation` 
WHERE tr.`operationType` = 2 
  AND tr.`routeNumber` != 0 
  AND tr.idStation != 0 
  AND tr.`idFiles` IN 
  (SELECT 
    fin.`idFiles` 
  FROM
    files_in fin 
  WHERE fin.`idTerminal` LIKE 'V%') 
  AND rm.`routeNumber` IS NOT NULL 
ORDER BY rm.`routeNumber`

此查询正常工作(至少有limit 1000限制)。但是,当我尝试更改为仅输出非重复的rm. routeNumber值时:

SELECT 
  DISTINCT rm.`routeNumber`
FROM
  ...

此查询开始起作用,似乎无限制地工作。瓶颈是transaction表,因为该表包含大量数据(255679420行),并且缺少索引(例如,此表中查询的任何列上都没有索引,除了idFiles)。我在idStation列添加了索引,并按以下方式更改了查询:

SELECT rm_dist.`routeNumber`
FROM
(SELECT 
   DISTINCT rm.`routeNumber`, rm.`idStation`
FROM
  route_map rm,
  station s
WHERE rm.`routeNumber` IS NOT NULL 
AND rm.`idStation` = s.idStation) rm_dist

WHERE EXISTS (
  SELECT *
   FROM transactions tr
   WHERE tr.`operationType` = 2 
    AND tr.`routeNumber` != 0 
    AND tr.idStation != 0 
    AND tr.`idFiles` IN  (SELECT fin.`idFiles` FROM files_in fin WHERE fin.`idTerminal` LIKE 'V%') 
    AND tr.`idStation` = rm_dist.`idStation`
    AND rm_dist.`routeNumber` = CONCAT(
            tr.`routeNumber`, 
            IF(tr.`letterOfRoute` REGEXP '[0-9]+' OR tr.`letterOfRoute` IS NULL,
               '',
               tr.`letterOfRoute`)
        )
);

但没有改变。无论如何,查询似乎无限地工作,等待查询执行结束是没用的。有没有其他方法可以改善这个查询?

1 个答案:

答案 0 :(得分:0)

尝试使用内部联接而不是IN子句,并避免使用无用的子选择

  SELECT 
     DISTINCT rm.`routeNumber`
  FROM
    route_map rm,
    station s
  WHERE rm.`routeNumber` IS NOT NULL 
  AND rm.`idStation` = s.idStation

  WHERE EXISTS (
    SELECT *
     FROM transactions tr
     INNER JOIN (
        SELECT fin.`idFiles` FROM files_in fin WHERE fin.`idTerminal` LIKE 'V%'
     ) T on tr.`idFiles` = t.`idFiles`
     WHERE tr.`operationType` = 2 
      AND tr.`routeNumber` != 0 
      AND tr.idStation != 0 
      AND tr.`idStation` = rm.`idStation`
      AND rm.`routeNumber` = CONCAT(
              tr.`routeNumber`, 
              IF(tr.`letterOfRoute` REGEXP '[0-9]+' OR tr.`letterOfRoute` IS NULL,
                 '',
                 tr.`letterOfRoute`)
          )
  );