gpt4 book ai didi

Mysql分区查询性能

转载 作者:行者123 更新时间:2023-12-04 04:22:36 25 4
gpt4 key购买 nike

我已经在定价表上创建了分区。下面是更改语句。

ALTER TABLE `price_tbl` 
PARTITION BY HASH(man_code)
PARTITIONS 87;

一个分区包含435510条记录。 price_tbl 中的总记录数为 600 万。

EXPLAIN query showing only one partion is used for the query。查询仍然需要 3-4 秒 来执行。下面是查询

 EXPLAIN SELECT vrimg.image_cap_id,vm.man_name,vr.range_code,vr.range_name,vr.range_url, MIN(`finance_rental`) AS from_price, vd.der_id AS vehicle_id FROM `range_tbl` vr 
LEFT JOIN `image_tbl` vrimg ON vr.man_code = vrimg.man_code AND vr.type_id = vrimg.type_id AND vr.range_code = vrimg.range_code
LEFT JOIN `manufacturer_tbl` vm ON vr.man_code = vm.man_code AND vr.type_id = vm.type_id
LEFT JOIN `derivative_tbl` vd ON vd.man_code=vm.man_code AND vd.type_id = vr.type_id AND vd.range_code=vr.range_code
LEFT JOIN `price_tbl` vp ON vp.vehicle_id = vd.der_id AND vd.type_id = vp.type_id AND vp.product_type_id=1 AND vp.maintenance_flag='N' AND vp.man_code=164
AND vp.initial_rentals_id =(SELECT rental_id FROM `rentals_tbl` WHERE rental_months='9')
AND vp.annual_mileage_id =(SELECT annual_mileage_id FROM `mileage_tbl` WHERE annual_mileage='8000')
WHERE vr.type_id = 1 AND vm.man_url = 'audi' AND vd.type_id IS NOT NULL GROUP BY vd.der_id

EXPLAIN 的结果。

enter image description here

没有分区的相同查询需要 3-4 秒。分区查询需要 2-3 秒。

我们如何提高查询性能,因为它太慢了。

附上创建表结构

  1. 价格表 - 包含 600 万条记录
CREATE TABLE `price_tbl` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`lender_id` bigint(20) DEFAULT NULL,
`type_id` bigint(20) NOT NULL,
`man_code` bigint(20) NOT NULL,
`vehicle_id` bigint(20) DEFAULT NULL,
`product_type_id` bigint(20) DEFAULT NULL,
`initial_rentals_id` bigint(20) DEFAULT NULL,
`term_id` bigint(20) DEFAULT NULL,
`annual_mileage_id` bigint(20) DEFAULT NULL,
`ref` varchar(255) DEFAULT NULL,
`maintenance_flag` enum('Y','N') DEFAULT NULL,
`finance_rental` decimal(20,2) DEFAULT NULL,
`monthly_rental` decimal(20,2) DEFAULT NULL,
`maintenance_payment` decimal(20,2) DEFAULT NULL,
`initial_payment` decimal(20,2) DEFAULT NULL,
`doc_fee` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`,`type_id`,`man_code`),
KEY `type_id` (`type_id`),
KEY `vehicle_id` (`vehicle_id`),
KEY `term_id` (`term_id`),
KEY `product_type_id` (`product_type_id`),
KEY `finance_rental` (`finance_rental`),
KEY `type_id_2` (`type_id`,`vehicle_id`),
KEY `maintenanace_idx` (`maintenance_flag`),
KEY `lender_idx` (`lender_id`),
KEY `initial_idx` (`initial_rentals_id`),
KEY `man_code_idx` (`man_code`)
) ENGINE=InnoDB AUTO_INCREMENT=5830708 DEFAULT CHARSET=latin1
/*!50100 PARTITION BY HASH (man_code)
PARTITIONS 87 */
  1. 派生表 - 这包含 18k 条记录。
CREATE TABLE `derivative_tbl` (
`type_id` bigint(20) DEFAULT NULL,
`der_cap_code` varchar(20) DEFAULT NULL,
`der_id` bigint(20) DEFAULT NULL,
`body_style_id` bigint(20) DEFAULT NULL,
`fuel_type_id` bigint(20) DEFAULT NULL,
`trans_id` bigint(20) DEFAULT NULL,
`man_code` bigint(20) DEFAULT NULL,
`range_code` bigint(20) DEFAULT NULL,
`model_code` bigint(20) DEFAULT NULL,
`der_name` varchar(255) DEFAULT NULL,
`der_url` varchar(255) DEFAULT NULL,
`der_intro_year` date DEFAULT NULL,
`der_disc_year` date DEFAULT NULL,
`der_last_spec_date` date DEFAULT NULL,
KEY `der_id` (`der_id`),
KEY `type_id` (`type_id`),
KEY `man_code` (`man_code`),
KEY `range_code` (`range_code`),
KEY `model_code` (`model_code`),
KEY `body_idx` (`body_style_id`),
KEY `capcodeidx` (`der_cap_code`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
  1. 范围表 - 这包含 1k 条记录
CREATE TABLE `range_tbl` (
`type_id` bigint(20) DEFAULT NULL,
`man_code` bigint(20) DEFAULT NULL,
`range_code` bigint(20) DEFAULT NULL,
`range_name` varchar(255) DEFAULT NULL,
`range_url` varchar(255) DEFAULT NULL,
KEY `range_code` (`range_code`),
KEY `type_id` (`type_id`),
KEY `man_code` (`man_code`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

最佳答案

如果您希望提高性能,

PARTITION BY HASH 基本上是无用的。 BY RANGE少数用例中很有用_。

大多数情况下,索引的改进与尝试使用分区一样好。

一些可能的问题:

  • InnoDB 表没有明确的 PRIMARY KEY。添加自然 PK(如果适用),否则添加 AUTO_INCREMENT
  • 没有“复合”索引——它们通常可以提高性能。示例:vrvrimg 之间的LEFT JOIN 涉及3 列; “右”表中这 3 列的复合索引可能有助于提高性能。
  • 盲目使用 BIGINT 而较小的数据类型可以工作。 (当表很大时,这是一个 I/O 问题。)
  • VARCHAR 中盲目使用 255。
  • 考虑是否大多数列都应该是NOT NULL
  • 该查询可能是“爆炸-内爆”综合症的受害者。这是您执行 JOIN(s) 的地方,它创建一个大的中间表,然后是 GROUP BY 以减少行数。
  • 不要使用 LEFT 除非“右”表确实是可选的。 (我看到 LEFT JOIN vd ... vd.type_id IS NOT NULL。)
  • 不要规范化“连续”值(annual_mileage 和 rental_months)。它对“=”测试并没有真正的好处,而且会严重损害“范围”测试的性能。

Same query without partitioning takes 3-4 sec. Query with partitioning takes 2-3 sec.

在分区和非分区之间切换时,索引几乎总是需要更改。对于每种情况的最佳索引,我预测性能将接近相同。

索引

无论是否分区,这些都应该有助于提高性能:

vm:     (man_url)
vr: (man_code, type_id) -- either order
vd: (man_code, type_id, range_code, der_id)
-- `der_id` 4th, else in any order (covering)
vrimg: (man_code, type_id, range_code, image_cap_id)
-- `image_cap_id` 4th, else in any order (covering)
vp: (type_id, der_id, product_type_id, maintenance_flag,
initial_rentals, annual_mileage, man_code)
-- any order (covering)

“覆盖”索引是一个额外的提升,因为它可以在索引的 BTree 中完成所有工作,而无需触及数据的 BTree。

实现我推荐的一系列内容,然后返回(在另一个问题中)进行进一步调整。

通常“分区键”应该放在复合索引的最后。

关于Mysql分区查询性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58747820/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com