在大型 table 上使用 LEFT JOIN 查询真的很慢

Query with LEFT JOIN on large table really slow

执行以下查询大约需要 12 秒。我试过优化但没能做到。要加入的 table 相当大(> 8.000.000 条记录)。

SELECT 
    p0_.id AS id_0, 
    p0_.ean AS ean_1, 
    p0_.brand AS brand_2, 
    p0_.type AS type_3, 
    p0_.retail_price AS retail_price_4, 
    p0_.target_price AS target_price_5, 
    min(NULLIF(c1_.delivery_price, 0)) AS sclr_6, 
    COALESCE(((p0_.target_price - min(NULLIF(c1_.delivery_price, 0))) / p0_.target_price * -100), 0) AS sclr_7 
FROM product p0_ 
LEFT JOIN crawl c1_ ON (
    c1_.product_ean = p0_.ean AND (
        c1_.crawl_date = p0_.last_crawl_date OR 
        p0_.last_crawl_date IS NULL
    ) 
    AND c1_.source_id IN (
        SELECT o2_.source_id AS sclr_8 
        FROM organisation_source o2_ 
        WHERE o2_.organisation_id = 5
    )
) 
WHERE p0_.organisation_id = 5 GROUP BY p0_.ean

我已经尝试过用很多不同的方式编写查询,但遗憾的是没有给我带来任何性能上的提升。如果我在最后删除子查询并且它也没有帮助。

查看下面 EXPLAIN 语句的输出:

+------+--------------+-------+------+---------------------------------------------------+------------------+---------+------------------------+--------+-------------+
| id   | select_type  | table | type | possible_keys                                     | key              | key_len | ref                    | rows   | Extra       |
+------+--------------+-------+------+---------------------------------------------------+------------------+---------+------------------------+--------+-------------+
|    1 | PRIMARY      | p0_   | ref  | uniqueConstraint,IDX_D34A04AD9E6B1585             | uniqueConstraint | 5       | const                  |     69 | Using where |
|    1 | PRIMARY      | c1_   | ref  | IDX_product_ean,IDX_crawl_date                    | IDX_product_ean  | 62      | admin_pricev-p.p0_.ean | 468459 | Using where |
|    2 | MATERIALIZED | o2_   | ref  | PRIMARY,IDX_DD91A56E9E6B1585,IDX_DD91A56E953C1C61 | PRIMARY          | 4       | const                  |      1 | Using index |
+------+--------------+-------+------+---------------------------------------------------+------------------+---------+------------------------+--------+-------------+

请参阅下面的产品和爬网表的 CREATE TABLE 语句:

CREATE TABLE `product` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `organisation_id` int(11) DEFAULT NULL,
  `ean` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
  `brand` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `type` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `retail_price` decimal(10,2) NOT NULL,
  `target_price` decimal(10,2) NOT NULL,
  `last_crawl_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniqueConstraint` (`organisation_id`,`ean`),
  KEY `IDX_D34A04AD9E6B1585` (`organisation_id`),
  KEY `IDX_target_price` (`target_price`),
  KEY `IDX_ean` (`ean`),
  KEY `IDX_type` (`type`),
  KEY `IDX_last_crawl_date` (`last_crawl_date`),
  CONSTRAINT `FK_D34A04AD9E6B1585` FOREIGN KEY (`organisation_id`) REFERENCES `organisation` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=927 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

CREATE TABLE `crawl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `source_id` int(11) DEFAULT NULL,
  `store_id` int(11) DEFAULT NULL,
  `product_ean` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
  `crawl_date` datetime NOT NULL,
  `takeaway_price` decimal(10,2) DEFAULT NULL,
  `delivery_price` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_B4E9F1C2953C1C61` (`source_id`),
  KEY `IDX_B4E9F1C2B092A811` (`store_id`),
  KEY `IDX_product_ean` (`product_ean`),
  KEY `IDX_takeaway_price` (`takeaway_price`),
  KEY `IDX_crawl_date` (`crawl_date`),
  CONSTRAINT `FK_B4E9F1C2953C1C61` FOREIGN KEY (`source_id`) REFERENCES `source` (`id`),
  CONSTRAINT `FK_B4E9F1C2B092A811` FOREIGN KEY (`store_id`) REFERENCES `store` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8606874 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

有人知道如何提高此查询的性能吗?非常感谢!如果需要更多信息,请告诉我!

您可以将查询简化为:

SELECT . . .
FROM product p0_  LEFT JOIN
     crawl c1_
     ON c1_.product_ean = p0_.ean AND 
        c1_.crawl_date = p0_.last_crawl_date AND
        EXISTS (SELECT 1
                FROM organisation_source o2_ 
                WHERE o2_.organisation_id = 5 AND c1_.source_id = o2_.source_id 
               )
WHERE p0_.organisation_id = 5
GROUP BY p0_.ean;

p0_.last_crawl_date IS NULL 大概是不必要的。 LEFT JOIN 会将所有行保留在第一个 table 中,即使在比较中有 NULL 也是如此。您的逻辑匹配第二个 table 中的 all 行(满足其他条件)。这可能是你想要的,但我猜不是。

在 MySQL 中,exists 有时比 in 快,这就是我重写该部分的原因。

对于此查询,您可以使用索引加快速度:product(organisation_id, ean, last_crawl_date)crawl(product_ean, crawl_date, source_id)organisation_source(source_id, organisation_id)

尝试在 LEFT JOINs

上使用复合索引
CREATE TABLE `product` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `organisation_id` int(11) DEFAULT NULL,
  `ean` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
  `brand` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `type` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `retail_price` decimal(10,2) NOT NULL,
  `target_price` decimal(10,2) NOT NULL,
  `last_crawl_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniqueConstraint` (`organisation_id`,`ean`),
  KEY `IDX_D34A04AD9E6B1585` (`organisation_id`),
  KEY `IDX_target_price` (`target_price`),
  KEY `IDX_ean` (`ean`),
  KEY `IDX_type` (`type`),
  KEY `IDX_last_crawl_date` (`last_crawl_date`),
  INDEX  `IDX_testing1` (`ean`,`last_crawl_date`),
  CONSTRAINT `FK_D34A04AD9E6B1585` FOREIGN KEY (`organisation_id`) REFERENCES `organisation` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=927 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

CREATE TABLE `crawl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `source_id` int(11) DEFAULT NULL,
  `store_id` int(11) DEFAULT NULL,
  `product_ean` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
  `crawl_date` datetime NOT NULL,
  `takeaway_price` decimal(10,2) DEFAULT NULL,
  `delivery_price` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_B4E9F1C2953C1C61` (`source_id`),
  KEY `IDX_B4E9F1C2B092A811` (`store_id`),
  KEY `IDX_product_ean` (`product_ean`),
  KEY `IDX_takeaway_price` (`takeaway_price`),
  KEY `IDX_crawl_date` (`crawl_date`),
  INDEX  `IDX_testing2` ( `source_id`,`product_ean`,`crawl_date`),
  CONSTRAINT `FK_B4E9F1C2953C1C61` FOREIGN KEY (`source_id`) REFERENCES `source` (`id`),
  CONSTRAINT `FK_B4E9F1C2B092A811` FOREIGN KEY (`store_id`) REFERENCES `store` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8606874 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci