【问题标题】:Too many cartesian products, making query to run slower笛卡尔积太多,使查询运行速度变慢
【发布时间】:2015-04-22 01:57:56
【问题描述】:

考虑一下我有两个表格 DETAILS AND RATE 以下列:

详细信息表:

CREATE TABLE DETAILS(
LONG ID PRIMARY KEY AUTO_INCREMENT,
DOUBLE PRICE1,
DOUBLE PRICE2,
DOUBLE PRICE3,
VARCHAR(25) CURRENCY,
DATE CREATED_DATE,
VARCHAT(50) COMPLETED
..................
Few more columns
);

价格表:

CREATE TABLE RATE(
LONG ID PRIMARY KEY AUTO_INCREMENT,
DOUBLE RATE,
VARCHAR(25) CURRENCY,
DATE CREATED_DATE
..................
Few more columns
);

我有一个 DETAILS 表的更新查询,如下所示。

UPDATE DETAILS D, RATE R 
SET D.PRICE1=D.PRICE1*R.RATE,
D.PRICE2=D.PRICE2*R.RATE,
D.PRICE3=D.PRICE3*R.RATE
WHERE
D.CURRENCY=R.CURRENCY AND 
DATE(D.CREATED_DATE) = DATE(R.CREATED_DATE) AND
D.COMPLETED IS NULL OR DO.COMPLETED='ABC' AND
D.CURRENCY!='RUPEE';

在查询正常运行之前,但随着表的增长,此查询开始花费更多时间,并且它以 十亿 的形式给出了笛卡尔积。

有什么办法可以优化这个查询吗? 任何帮助将不胜感激。

【问题讨论】:

  • 你能发布EXPLAIN UPDATE....查询的输出吗?
  • 你能列出你在每张表上的索引吗?
  • 嗨,Simon,对于每次运行,我们都会在两个表中插入新数据,一旦插入数据,我们就会调用此更新查询来更新数据。
  • 马克,除了主键之外,我们没有这些表的索引

标签: mysql query-optimization cartesian-product


【解决方案1】:

DATE(D.CREATED_DATE) = DATE(R.CREATED_DATE)

由于这些字段是 DATE 数据类型,因此无需使用 DATE() 函数。事实上,这样做会阻止使用索引。

至少将INDEX(currency, created_date) 添加到RATE。这一点,加上上面的改动,将大大加快查询速度。

另一个改进是使 currency 成为 ENUM 或对其进行规范化。

【讨论】:

    【解决方案2】:

    使用显式joins 并使用括号修正where 子句:

    UPDATE DETAILS D JOIN
           RATE R 
           ON D.CURRENCY=R.CURRENCY AND 
              DATE(D.CREATED_DATE) = DATE(R.CREATED_DATE)
      SET D.PRICE1 = D.PRICE1*R.RATE,
          D.PRICE2 = D.PRICE2*R.RATE,
          D.PRICE3 = D.PRICE3*R.RATE
    WHERE (D.COMPLETED IS NULL OR DO.COMPLETED='ABC') AND
          D.CURRENCY <> 'RUPEE';
    

    问题在于where 子句中的括号。但是,您根本不应该使用逗号来表示 join

    【讨论】:

      猜你喜欢
      • 2017-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-28
      • 2017-06-29
      • 2015-09-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多