mySQL - UNION语句的性能

时间:2013-10-09 04:49:46

标签: mysql sql nested-queries dynamic-queries

我需要将两个具有相同列的表组合在一起,并在复杂的JOIN查询中使用结果,但它会大大降低性能。使用UNIONs的此查询的执行时间为7秒:

SELECT DISTINCT `admin`.`Fund_ID`,
                `admin`.`Fund_Name`
FROM (
        (SELECT *
         FROM `admin`)
      UNION
        (SELECT *
         FROM `admin_custom`
         WHERE `user_id`=361)) admin
LEFT JOIN (
             (SELECT *
              FROM `quant1`)
           UNION
             (SELECT *
              FROM `quant1_cust`
              WHERE `user_id`=361)) quant1 
ON (quant1.`Fund ID`=`admin`.`Fund_ID`)
WHERE quant1.`VaR 95`>-0.028

但是用简单的表替换UNION子句只需0.006秒。如何解决性能问题?

2 个答案:

答案 0 :(得分:0)

您可以对数据库进行“附加更改”,以创建UNIONED表之间的通用性。这将是一个重构只添加表格&列,保持与未更改的应用程序代码的读取兼容性。

在此示例中,您将在“adminadmin_custom左侧创建一个公用表格,然后将其加入。这将有基金ID,TYPE(所以你知道你加入了哪个),如果可能的话,还有其他有用的公共列。

您还可以在“quant1quant1_cust左侧创建一个公用表格,然后从加入

然后,您将更改查询以使用公用表中的Fund-ID链接,将UNION子句替换为“Common Table”(如果可能)或"Common Table" left outer join Legacy1 left outer join Legacy2

我不明白这些表格到底是什么,所以我无法帮助你明智地命名。 (命名是设计中最重要的部分,你应该在你的问题中对此进行解释。)

但是这种方法对我领导的一个重大政府项目非常有效,其中常见的表格是DOCUMENT和DOC_ELEMENT。具有8种不同文档类型且没有预先存在的通用性的树状结构文档。

在我们的案例中,DOCUMENT被添加到“RFP,TENDER,PRICEPLAN等”的左侧,并提供了共性。

这不是完全向后兼容性 - 您需要更改应用程序的INSERT代码。如果您正在进行重构,您可能需要考虑将相同的表结构放在同一个表中

最好的办法是试验可能的结构,验证可能的性能,并确定需要哪些代码更改。然后你可以选择一个轨迹。

答案 1 :(得分:0)

这涉及一些猜测 - admin仅涉及quant1吗?和admin_custom只是quant1_cust?然后,这应该减少这两个字段的不同列表所需的工作量:

SELECT `Fund_ID`, `Fund_Name`
FROM `admin`
INNER JOIN `quant1` ON `admin`.`Fund_ID` = `quant1`.`Fund_ID`
                   AND `quant1`.`VaR 95`>-0.028

UNION

SELECT `Fund_ID`, `Fund_Name`
FROM `admin_custom`
INNER JOIN `quant1_cust` ON `admin_custom`.`Fund_ID` = `quant1_cust`.`Fund_ID`
                        AND `admin_custom`.`user_id` = `quant1_cust`.`user_id`
                        AND `quant1_cust`.`VaR 95`>-0.028
WHERE `admin_custom`.`user_id`=361
;

查看您现有的查询结构,我建议您不要做几件事。使用UNION和SELECT DISTINCT毫无意义。不要将select *与UNION或UNION ALL一起使用 - 具体而且只涉及您真正需要的字段。并且您现有的where子句会抑制左连接返回的任何空值 - 所以不要使用左连接。

SELECT DISTINCT --<< effort for distinctiveness here
...
FROM (
      SELECT * --<< too many fields
      ...
      UNION --<< effort for distinctiveness here

      SELECT * --<< too many fields
      ...
     )
LEFT JOIN (
            SELECT * --<< too many fields
            ...
            UNION --<< effort for distinctiveness here

            SELECT * --<< too many fields
            ...
           ) quant1
WHERE quant1 ...

编辑:替代 - 对不起,按照这种方式可能更容易:

SELECT `Fund_ID`, `Fund_Name`
FROM `admin`
INNER JOIN `quant1` ON `admin`.`Fund_ID` = `quant1`.`Fund_ID`
WHERE `quant1`.`VaR 95`>-0.028

UNION

SELECT `Fund_ID`, `Fund_Name`
FROM `admin_custom`
INNER JOIN `quant1_cust` ON `admin_custom`.`Fund_ID` = `quant1_cust`.`Fund_ID`
                        AND `admin_custom`.`user_id` = `quant1_cust`.`user_id`
WHERE `admin_custom`.`user_id`=361
AND `quant1_cust`.`VaR 95`>-0.028
;