`我有一个简单的选择查询,以前在 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,使用它会增加响应时间
真的不明白为什么你需要子查询,它是多余的
如您所见,查询变得即时更快。
索引的数量乍一看似乎过多,你应该看看其他说明是否需要它们。
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 | 使用索引 |