MySQL选择没有子查询的最大值

时间:2014-07-29 16:08:14

标签: mysql sql performance greatest-n-per-group

关于这个主题有很多问题(例如,请参阅herehere),但我无法弄清楚如何正确运行我的具体案例。

以下是包含表架构,记录和查询的SQLFiddle。此时我有一个有效的查询,但效率非常低,因为它使用了一个从属子查询:

SELECT 
      id_document, version, id_plant_mov, id_production_type, is_ext, 
      id_cost_center, id_import_kpi_code, id_plant_tag, value 
FROM  document_production_history2 
WHERE id_document = 751 
  AND id_production_type IN (1, 3) 
  AND is_group_production = 0 
  AND (id_document, id_plant_mov, id_production_type, id_cost_center, 
       id_import_kpi_code, id_plant_tag, is_ext, version) 
      IN (
        SELECT id_document, id_plant_mov, id_production_type, 
               id_cost_center, id_import_kpi_code, id_plant_tag, is_ext, 
               MAX(version) 
        FROM document_production_history2 
        GROUP BY id_document, id_plant_mov, id_production_type, 
            id_cost_center, id_import_kpi_code, id_plant_tag, is_ext);

我试图像这样重写上面的查询:

SELECT d.id_document id_doc, d.version, d.id_plant_mov, 
    d.id_production_type id_prod_type, d.is_ext, d.id_cost_center, 
    d.id_import_kpi_code kpi_code, d.id_plant_tag, d.value 
FROM document_production_history2 d 
JOIN (
  SELECT id_document, id_plant_mov, id_production_type, is_ext, 
      id_cost_center, id_import_kpi_code, id_plant_tag, 
      is_group_production, MAX(version) version 
  FROM document_production_history2 
  WHERE id_document = 751 
  AND id_production_type IN (1, 3) 
  AND is_group_production = 0 
  GROUP BY id_document, id_plant_mov, id_production_type, 
      id_cost_center, id_import_kpi_code, id_plant_tag, 
      is_group_production
) m 
ON d.version = m.version 
AND d.id_document = m.id_document 
AND d.id_production_type = m.id_production_type 
AND d.id_plant_mov = m.id_plant_mov 
AND d.id_plant_tag = m.id_plant_tag 
AND d.id_cost_center = m.id_cost_center 
AND d.id_import_kpi_code = m.id_import_kpi_code 
AND d.is_ext = m.is_ext 
AND d.is_group_production = m.is_group_production;

但它返回27行而不是预期的10行。

提前致谢。

4 个答案:

答案 0 :(得分:1)

派生表是这里的方法。第二个示例中的问题是,您为返回的每一行获得了max(版本),包括is_group_production的差异 - 这是额外行悄悄进入的地方。因此,where子句需要保留在外部查询中。从理论上讲,你可以将where子句的另外两部分移动到内部查询中,但我发现它非常难以理解且不直观。

这将返回10行:

SELECT 
      d.id_document, d.version, d.id_plant_mov, d.id_production_type, d.is_ext, 
      d.id_cost_center, d.id_import_kpi_code, d.id_plant_tag, d.value 
FROM  
      document_production_history2  d JOIN

(SELECT id_document, id_plant_mov, id_production_type, 
       id_cost_center, id_import_kpi_code, id_plant_tag, is_ext, 
       MAX(VERSION) AS maxversion
 FROM document_production_history2 
 GROUP BY id_document, id_plant_mov, id_production_type, 
    id_cost_center, id_import_kpi_code, id_plant_tag, is_ext) m ON

  d.version = m.maxversion and 
  d.id_document = m.id_document and
  d.id_production_type = m.id_production_type  and
  d.id_plant_mov = m.id_plant_mov  and
  d.id_plant_tag = m.id_plant_tag  and
  d.id_cost_center = m.id_cost_center and 
  d.id_import_kpi_code = m.id_import_kpi_code and
  d.is_ext = m.is_ext 

WHERE 
  d.id_document = 751  and
  d.id_production_type IN (1, 3)  and
  d.is_group_production = 0 

据我所知,它的表现相当不错。派生表不是理想的解决方案,但它们比子查询更好一个数量级,因为mysql不必为结果集的每一行执行它们。

答案 1 :(得分:1)

这是JOIN,它等同于您的第一个查询。您需要从子查询中取出is_group_production = 0,并且只在主查询中执行。这会筛选出最大版本为组生产的行。

SELECT d.id_document id_doc, d.version, d.id_plant_mov, 
    d.id_production_type id_prod_type, d.is_ext, d.id_cost_center, 
    d.id_import_kpi_code kpi_code, d.id_plant_tag, d.value 
FROM document_production_history2 d 
JOIN (
  SELECT id_document, id_plant_mov, id_production_type, is_ext, 
      id_cost_center, id_import_kpi_code, id_plant_tag, 
      MAX(version) version 
  FROM document_production_history2 
  WHERE id_document = 751 
  AND id_production_type IN (1, 3) 
  GROUP BY id_document, id_plant_mov, id_production_type, 
      id_cost_center, id_import_kpi_code, id_plant_tag

) m 
ON d.version = m.version 
AND d.id_document = m.id_document 
AND d.id_production_type = m.id_production_type 
AND d.id_plant_mov = m.id_plant_mov 
AND d.id_plant_tag = m.id_plant_tag 
AND d.id_cost_center = m.id_cost_center 
AND d.id_import_kpi_code = m.id_import_kpi_code 
AND d.is_ext = m.is_ext 
WHERE d.is_group_production = 0;

DEMO

答案 2 :(得分:0)

此:

JOIN (
    SELECT id_document, id_plant_mov, id_production_type, is_ext, 
      id_cost_center, id_import_kpi_code, id_plant_tag, 
      is_group_production, MAX(version) version 
    FROM document_production_history2 
    WHERE id_document = 751 
    AND id_production_type IN (1, 3) 
    AND is_group_production = 0 
    GROUP BY id_document, id_plant_mov, id_production_type, 
      id_cost_center, id_import_kpi_code, id_plant_tag, 
      is_group_production
) m 

应该是这样的:

JOIN (
    SELECT id_document, MAX(version) version 
    FROM document_production_history2 
    WHERE id_document = 751 
    AND id_production_type IN (1, 3) 
    AND is_group_production = 0 
    GROUP BY id_document
) m 

加入m时,请使用id_document和仅版本。

答案 3 :(得分:-2)

为什么不完全删除子查询?

SELECT 
id_document, version, id_plant_mov, id_production_type, is_ext, 
id_cost_center, id_import_kpi_code, id_plant_tag, value, MAX(version) 
FROM  document_production_history2 
WHERE id_document = 751 
AND id_production_type IN (1, 3) 
AND is_group_production = 0
GROUP BY id_document, id_plant_mov, id_production_type, id_cost_center, id_import_kpi_code, id_plant_tag, is_ext