什么索引可以提高JOIN和GROUP BY的性能

时间:2018-10-25 11:32:40

标签: mysql performance indexing group-by query-performance

我已经设置了一些表并运行了一个查询。但是在我的解释中,它将在临时表中生成SQL结果(我认为这是由于GROUP BY)

我添加了一些索引来加快查询的速度,但是想知道是否有一种方法可以停止使用临时表,是否还有其他方法可以加快使用索引的查询速度?

CartData

CREATE TABLE `cartdata` (
    `IDCartData` INT(11) NOT NULL AUTO_INCREMENT,
    `CartOrderref` VARCHAR(25) NOT NULL DEFAULT '',
    `UserID` INT(11) NOT NULL DEFAULT '0',
    `LastUpdate` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 
    CURRENT_TIMESTAMP,
    `ManualContactName` VARCHAR(100) NOT NULL DEFAULT '',
    `ManualOrderConfirmationEmail` VARCHAR(100) NOT NULL DEFAULT '',
    PRIMARY KEY (`IDCartData`),
    INDEX `CartOrderref` (`CartOrderref`)
)

CartSplitData

    CREATE TABLE `cartsplitdata` (
        `IDCartSupplierData` INT(11) NOT NULL AUTO_INCREMENT,
        `IDCartData` INT(11) NOT NULL DEFAULT '0',
        `supplierid` INT(11) NOT NULL DEFAULT '0',
        `DeliveryDate` DATE NOT NULL DEFAULT '2000-01-01',
        `AccountNumber` VARCHAR(50) NOT NULL DEFAULT '',
        `ManualOrderref` VARCHAR(50) NOT NULL DEFAULT '',
        `lastupdate` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        PRIMARY KEY (`IDCartSupplierData`),
        INDEX `cartdatasupplierid` (`IDCartData`, `supplierid`)
    )

我的示例查询

        EXPLAIN SELECT max(CartData.idCartDATA) AS idCartDATA , CartData.*, CartSplitData.*
        FROM CartData
        JOIN CartSplitData ON CartSplitData.IDCartDATA = CartDATA.IDCartData
        WHERE  CartData.CartOrderref = 'XXXXXXXXX'
        group by CartSplitData.SUPPLIERID

说明查询结果 Explain of query results

1 个答案:

答案 0 :(得分:1)

专业提示在性能敏感的查询中避免使用SELECT *SELECT table.*。而是通过名称选择您实际需要使用的列

专业提示 MySQL对您正在使用的GROUP BY有一个臭名昭著的非标准扩展名,并且可能会滥用。读这个。 https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html如果您遵循第一个提示,那么跟随第二个提示会容易得多。

专业提示,避免“抛出”大量单列索引,以期加快查询速度。相反,创建索引(通常是复合索引)以匹配实际查询的需求。阅读此https://use-the-index-luke.com

出现在EXPLAIN输出中的

专业提示 Using temporary; using filesort不一定很糟糕。这仅表示查询引擎必须在返回部分结果集之前对其进行缓存。 temporary不是一个实际的表,它是一个RAM结构。如果它太大而导致RAM泛滥,MySQL会将其溢出到磁盘上。但是你不是。

所有这些,让我们重构您的查询。我猜您想为每个idCartDATA检索具有最大CartSplitData.SUPPLIERID值的行。

因此,我们将其写为子查询。

                  SELECT max(IDCartDATA) AS IDCartDATA, SUPPLIERID
                    FROM CartSplitData
                   GROUP BY SUPPLIERID

通过在CartSplitData:(SUPPLIERID, IDCartDATA)上添加复合索引,可以大大加快该查询的速度。

接下来,让我们重写您的主查询,以找到与该子查询中的ID相匹配的行。

SELECT CartData.*             /* * hammers performance */
       CartSplitData.*        /* * hammers performance */
  FROM CartData
  JOIN CartSplitData ON CartSplitData.IDCartDATA = CartDATA.IDCartData
  JOIN (
                  SELECT max(IDCartDATA) AS IDCartDATA, SUPPLIERID
                    FROM CartSplitData
                   GROUP BY SUPPLIERID
       )x ON x.SUPPLIERID = CartSplitData.SUPPLIERID
         AND x.IDCartData = CartSplitData.IDCartData
 WHERE CartData.CartOrderref = 'XXXXXXXXX'

您在CartData.CartOrderref上的索引以及复合索引创建的^^^都会帮助此外部查询。