Mysql 8.0.23 导致选择查询的性能大幅下降

问题描述 投票:0回答:1

`我有一个简单的选择查询,以前在 mysql 5.7 版本中需要 850 毫秒才能运行,现在运行时间超过 2 秒(具体为 2.20 秒)

SELECT c.id,
c.cart_type as cartType,
c.name,
c.storefront_id as storefrontId,
c.contact_id as contactId,
c.account_number as accountNumber,
c.ship_to as shipTo,
c.name1 as shipToName1,
c.name2 as shipToName2,
c.city,
c.country,
c.status,
c.order_type as orderType,
c.currency as currency,
c.updated_at as updatedOn,
CASE WHEN EXISTS (SELECT 1
FROM contact_active_cart cac
WHERE cac.cart_id = c.id) THEN 'true' ELSE 'false' END as isActive
FROM (SELECT id
FROM cart c
WHERE c.cart_type = 'cart'
AND c.storefront_id = 1
AND c.status IN (
7, 8, 6, 2, 0
)
AND c.account_number in (
'0100000106', '0100000212', '0100000806', '0100000860', '0100001329', '0100001537', '0100010879',     '0100012479', '0100012553', '0100012579'
        )
ORDER BY created_at ASC
LIMIT 0,
200 ) as cart_inner_subselect
INNER JOIN cart c ON cart_inner_subselect.id = c.id;

根据要求添加创建表:

CREATE TABLE `cart` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `contact_id` varchar(255) NOT NULL,
  `storefront_id` bigint NOT NULL,
  `cart_type` varchar(50) DEFAULT NULL,
  `status` tinyint(1) NOT NULL DEFAULT '0',
  `name` varchar(255) NOT NULL,
  `ship_to` varchar(255) NOT NULL,
  `account_number` varchar(40) DEFAULT NULL,
   `name1` varchar(35) DEFAULT NULL,
  `name2` varchar(35) DEFAULT NULL, `city` varchar(35) DEFAULT NULL,
  `state` varchar(80) DEFAULT NULL,
  `country` varchar(80) DEFAULT NULL,
  `order_type` varchar(5) DEFAULT NULL,
  `currency` varchar(3) DEFAULT NULL
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk-cart` (`contact_id`,`storefront_id`,`name`,`cart_type`,`submission_datetime`),
  KEY `idx-cart-cart_type` (`cart_type`),
  KEY `idx-cart-cart_overview_1` (`cart_type`,`storefront_id`,`status`,`account_number`,`created_at`),
  KEY `idx-cart-cart_overview_contact` (`cart_type`,`storefront_id`,`status`,`account_number`,`contact_id`,`created_at`),
  KEY `idx-cart-cart_overview_shipTo` (`cart_type`,`storefront_id`,`status`,`account_number`,`ship_to`,`created_at`),
  KEY `idx-cart-cart_overview_all` (`cart_type`,`storefront_id`,`status`,`account_number`,`contact_id`,`ship_to`,`created_at`)
) ENGINE=InnoDB AUTO_INCREMENT=24331499 DEFAULT CHARSET=utf8mb3;

CREATE TABLE `contact_active_cart` (
  `contact_id` varchar(255) NOT NULL,
  `cart_id` bigint NOT NULL,
  `storefront_id` bigint NOT NULL,
  PRIMARY KEY (`contact_id`,`storefront_id`),
  KEY `idx-contact_active_cart-cart_id` (`cart_id`),
  KEY `idx-contact_active_cart-contact_id` (`contact_id`),
  KEY `idx-contact_active_cart-storefront_id` (`storefront_id`),
  CONSTRAINT `contact_active_cart_FK` FOREIGN KEY (`cart_id`) REFERENCES `cart` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

我在 cart_type、storefront_id、status、account_number 上添加了索引。所以,当我过去在 5.7 版本上运行这个时,索引被正确拾取,而在 8.0 中它没有拾取,并且所花费的时间比以前要长得多。

里面的数据说购物车表大约有600M。请提出任何改进建议,或者我应该升级到任何更高版本才能看到性能改进。`

除了要求检查解释之外:我尝试在我正在使用的索引中添加created_at(索引idx-cart-cart_overview_1),它减少了时间,但所花费的时间仍然高于我在5.7版本中获得的时间。另外,假设我在 where 子句中添加任何其他过滤器(例如 contact_id 或 Ship_to),它完全忽略应该使用的索引并引用 idx-cart-cart_type,使用它会增加响应时间

java mysql performance query-optimization mysql-8.0
1个回答
0
投票

真的不明白为什么你需要子查询,它是多余的

如您所见,查询变得即时更快。

索引的数量乍一看似乎过多,你应该看看其他说明是否需要它们。

CREATE TABLE `cart` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `contact_id` varchar(255) NOT NULL,
  `storefront_id` bigint NOT NULL,
  `cart_type` varchar(50) DEFAULT NULL,
  `status` tinyint(1) NOT NULL DEFAULT '0',
  `name` varchar(255) NOT NULL,
  `ship_to` varchar(255) NOT NULL,
  `account_number` varchar(40) DEFAULT NULL,
   `name1` varchar(35) DEFAULT NULL,
  `name2` varchar(35) DEFAULT NULL, `city` varchar(35) DEFAULT NULL,
  `state` varchar(80) DEFAULT NULL,
  `country` varchar(80) DEFAULT NULL,
  `order_type` varchar(5) DEFAULT NULL,
  `currency` varchar(3) DEFAULT NULL,
  `submission_datetime` datetime,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk-cart` (`contact_id`,`storefront_id`,`name`,`cart_type`,`submission_datetime`),
  KEY `idx-cart-cart_type` (`cart_type`),
  KEY `idx-cart-cart_overview_1` (`cart_type`,`storefront_id`,`status`,`account_number`,`created_at`),
  KEY `idx-cart-cart_overview_contact` (`cart_type`,`storefront_id`,`status`,`account_number`,`contact_id`,`created_at`),
  KEY `idx-cart-cart_overview_shipTo` (`cart_type`,`storefront_id`,`status`,`account_number`,`ship_to`,`created_at`),
  KEY `idx-cart-cart_overview_all` (`cart_type`,`storefront_id`,`status`,`account_number`,`contact_id`,`ship_to`,`created_at`)
) ENGINE=InnoDB AUTO_INCREMENT=24331499 DEFAULT CHARSET=utf8mb3;


CREATE TABLE `contact_active_cart` (
  `contact_id` varchar(255) NOT NULL,
  `cart_id` bigint NOT NULL,
  `storefront_id` bigint NOT NULL,
  PRIMARY KEY (`contact_id`,`storefront_id`),
  KEY `idx-contact_active_cart-cart_id` (`cart_id`),
  KEY `idx-contact_active_cart-contact_id` (`contact_id`),
  KEY `idx-contact_active_cart-storefront_id` (`storefront_id`),
  CONSTRAINT `contact_active_cart_FK` FOREIGN KEY (`cart_id`) REFERENCES `cart` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
EXPLAIN SELECT c.id,
c.cart_type as cartType,
c.name,
c.storefront_id as storefrontId,
c.contact_id as contactId,
c.account_number as accountNumber,
c.ship_to as shipTo,
c.name1 as shipToName1,
c.name2 as shipToName2,
c.city,
c.country,
c.status,
c.order_type as orderType,
c.currency as currency,
c.updated_at as updatedOn,
CASE WHEN EXISTS (SELECT 1
FROM contact_active_cart cac
WHERE cac.cart_id = c.id) THEN 'true' ELSE 'false' END as isActive
FROM (SELECT id
FROM cart c
WHERE c.cart_type = 'cart'
AND c.storefront_id = 1
AND c.status IN (
7, 8, 6, 2, 0
)
AND c.account_number in (
'0100000106', '0100000212', '0100000806', '0100000860', '0100001329', '0100001537', '0100010879',     '0100012479', '0100012553', '0100012579'
        )
ORDER BY created_at ASC
LIMIT 0,
200 ) as cart_inner_subselect
INNER JOIN cart c ON cart_inner_subselect.id = c.id;
id 选择类型 桌子 分区 类型 可能的键 key_len 参考 过滤 额外
1 小学 c 全部 小学 1 100.00
1 小学 参考 8 fiddle.c.id 2 100.00 使用索引
3 派生 c 参考 idx-cart-cart_type、idx-cart-cart_overview_1、idx-cart-cart_overview_contact、idx-cart-cart_overview_shipTo、idx-cart-cart_overview_all idx-购物车-cart_type 153 常量 1 100.00 使用地点;使用文件排序
2 依赖子查询 cac 参考 idx-contact_active_cart-cart_id idx-contact_active_cart-cart_id 8 fiddle.c.id 1 100.00 使用索引

EXPLAIN SELECT 
    c.id,
    c.cart_type AS cartType,
    c.name,
    c.storefront_id AS storefrontId,
    c.contact_id AS contactId,
    c.account_number AS accountNumber,
    c.ship_to AS shipTo,
    c.name1 AS shipToName1,
    c.name2 AS shipToName2,
    c.city,
    c.country,
    c.status,
    c.order_type AS orderType,
    c.currency AS currency,
    c.updated_at AS updatedOn,
    CASE
        WHEN
            EXISTS( SELECT 
                    1
                FROM
                    contact_active_cart cac
                WHERE
                    cac.cart_id = c.id)
        THEN
            'true'
        ELSE 'false'
    END AS isActive
FROM
        cart c
    WHERE
        c.cart_type = 'cart'
            AND c.storefront_id = 1
            AND c.status IN (7 , 8, 6, 2, 0)
            AND c.account_number IN ('0100000106' , '0100000212', '0100000806', '0100000860', '0100001329', '0100001537', '0100010879', '0100012479', '0100012553', '0100012579')
    ORDER BY created_at ASC
    LIMIT 0 , 200;
id 选择类型 桌子 分区 类型 可能的键 key_len 参考 过滤 额外
1 小学 c 参考 idx-cart-cart_type、idx-cart-cart_overview_1、idx-cart-cart_overview_contact、idx-cart-cart_overview_shipTo、idx-cart-cart_overview_all idx-购物车-cart_type 153 常量 1 100.00 使用地点;使用文件排序
2 依赖子查询 cac 参考 idx-contact_active_cart-cart_id idx-contact_active_cart-cart_id 8 fiddle.c.id 1 100.00 使用索引

小提琴

© www.soinside.com 2019 - 2024. All rights reserved.