Mysql分区查询性能

Mysql分区查询性能,mysql,partitioning,mysql-5.7,Mysql,Partitioning,Mysql 5.7,我已经在定价表上创建了分区。下面是alter语句 ALTER TABLE `price_tbl` PARTITION BY HASH(man_code) PARTITIONS 87; 一个分区由435510条记录组成。价格总记录为600万 EXPLAIN查询仅显示一个部分用于查询。不过,执行查询需要3-4秒。下面是查询 EXPLAIN SELECT vrimg.image_cap_id,vm.man_name,vr.range_code,vr.range_name,vr.range_url

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

ALTER TABLE `price_tbl` 
PARTITION BY HASH(man_code)
PARTITIONS 87;
一个分区由435510条记录组成。价格总记录为600万

EXPLAIN查询仅显示一个部分用于查询。不过,执行查询需要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
解释的结果

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

如何在查询速度太慢的情况下提高查询性能

附件创建表结构。

  • 价格表-包含600万条记录
  • 衍生表-由18k条记录组成
  • 范围表-由1k条记录组成

  • 如果希望提高性能,则按哈希进行分区基本上是无用的<代码>按范围在一些用例中很有用

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

    一些可能的问题:

    • InnoDB表没有显式的
      主键
      。如果适用,添加一个自然PK,否则为
      自动增量
    • 没有“复合”索引——它们通常提供性能提升。示例:
      vr
      vrimg
      之间的
      LEFT JOIN
      包含3列;“right”表中这3列上的复合索引可能有助于提高性能
    • 当较小的数据类型可以工作时,盲目使用
      BIGINT
      。(当表很大时,这是一个I/O问题。)
    • VARCHAR
      中盲目使用255
    • 考虑大多数列是否应为
      非NULL
    • 这种质疑可能是“爆炸-内爆”综合症的受害者。这是执行
      JOIN(s)
      的地方,它创建了一个大的中间表,然后是一个
      groupby
      ,以减少行计数
    • 不要使用
      LEFT
      ,除非“right”表确实是可选的。(我看到
      左连接vd…vd.type\u id不为空
    • 不要规范化“连续”值(年里程和租赁月)。这对“=”测试并没有真正的好处,而且严重影响了“范围”测试的性能
    没有分区的相同查询需要3-4秒。带分区的查询需要2-3秒

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

    索引

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

    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 5.7.5+启用了sql\u模式,由于支持功能依赖性检测,因此只有完整的组才能信任此查询,而您在这里信任的是。。假设查询依赖于功能,我没有检查…分区并不是性能提升(jet)的sllver子弹,将来随着MySQL开发团队致力于InnoDB引擎的支持,它可能会改变。。还有一篇文章确实表明它仍然很有限,但这是一个好的开始,我们对此等了很久?。。。。。此外,从查询和解释的角度来看,我非常确定SQL重新编译是获得更好性能的最佳选择,因为优化器将以“错误”的顺序访问表,以防止临时表和排序。请参阅以提供示例数据和预期结果,以便我们可以验证SQL重写。。还要执行一个
    SHOW VERSION()
    ,因为MySQL优化器在主要的MySQL版本之间可能会有很大的差异。其他信息请求。在pastebin.com上发布并共享链接。RAM大小,#内核,MySQL主机服务器上的任何SSD设备从SSH登录根目录,文本结果为:B)显示全局状态;至少24小时正常运行后C)显示全局变量;D) 显示完整的进程列表;E) 完整的MySQLTuner报告和可选的非常有用的信息,如果可用,包括-htop或top或mytop(适用于大多数活动应用程序),ulimit-a(适用于linux/unix限制列表),iostat-xm 5 3(适用于按设备和核心/cpu计数划分的IOPS),用于服务器工作负载优化分析以提供建议。
    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
    
    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
    
    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)