为什么分库分表后不建议跨分片查询
来源:阿飞的博客
写在前面:如果对分库分表还不是很熟悉的,可以参考笔者之前的文章《分库分表技术演进&最佳实践》。
在这篇文章中提到了一个场景,即电商的订单。我们都知道订单表有三大主要查询:基于订单ID查询,基于商户编号查询,基于用户ID查询。且那篇文章给出的方案是基于订单ID、商户编号、用户ID都有一份分库分表的数据。那么为什么要这么做?能否只基于某一列例如用户ID分库分表,答案肯定是不能。
笔者基于sharding-sphere(GitHub地址:https://github.com/apache/incubator-shardingsphere)进行了一个简单的测试,测试环境如下:
128个分表:image_${0..127};
数据库服务器:32C64G;
数据库版本:MySQL-5.7.23;
操作系统:CentOS 6.9 Final;
连接池:druid 1.1.6;
mysql-connector-java:6.0.5;
mybatis:3.4.5;
mybatis-spring:1.3.1;
springboot:1.5.9.RELEASE;
sharding-sphere-3.1.0;
JVM参数:-Xmx2g -Xms2g -Xmn1g -Xss256k -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+AlwaysPreTouch;
druid配置:默认参数;
表信息如下:
-- id是分片键。备注,DDL是伪SQLCREATE TABLE `image_${0..127}` ( `id` varchar(32) NOT NULL, `image_no` varchar(50) NOT NULL, `file_name` varchar(200) NOT NULL COMMENT '影像文件名称', `source` varchar(32) DEFAULT NULL COMMENT '影像来源', `create_date` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '影像文件创建时间', PRIMARY KEY (`id`), KEY `idx_image_no` (`image_no`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
第1个测试场景如下:
每个分表大概160w数据;
累计1w次跨分片(imageNo)查询 PK. 带分片(id)查询;
测试结果如下:
结论:由测试结果可知,跨分片查询相比带分片键查询的性能衰减了很多。
第2个测试场景如下:
每个分表大概160w数据;
累计1w次分别测试跨1个分表,8个分表、16个分表、32个分表、64个分表、128个分表,结果如下:
结论:跨的分表数量越大,跨分表查询的性能越差;
为什么慢
我们要弄明白跨分片查询为什么这么慢之前,首先要掌握跨分片查询原理。以sharding-sphere为例,其跨分片查询的原理是:通过线程池并发请求到所有符合路由规则的目标分表,然后对所有结果进行归并。需要说明的是,当路由结果只有1个,即不跨分片操作时sharding-sphere不会通过线程池异步执行,而是直接同步执行,这么做的原因是为了减少线程开销,核心源码在ShardingExecuteEngine.java中)。
既然是这个执行原理,为什么跨分片查询,随着跨分片数量越多,性能会越来越差?我们再看一下第2个测试场景,当测试跨1个分表时,1w次查询只需要5889ms,即平均1次查询不到1ms。所以性能瓶颈不应该在SQL执行阶段,而应该在结果归并阶段。为了验证这个猜想,笔者空跑sharding-sphere依赖的并发执行组件google-guava的MoreExecutors。其结果如下:
结论:由这个测试结果可知,当并发执行越来越多,其结果归并的代价越来越大。
附--空跑sharding-sphere依赖的并发执行组件google-guava的MoreExecutors的部分源码如下:
public class ConcurrentExecutorTest { private static final ListeningExecutorService executorService; public static final int CONCURRENT_COUNT = 64; public static final int batchSize = CONCURRENT_COUNT; public static final int EXECUTOR_SIZE = 8; static { executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(EXECUTOR_SIZE)); MoreExecutors.addDelayedShutdownHook(executorService, 60, TimeUnit.SECONDS); }
private static <I, O> List<O> execute(final Collection<I> inputs) { if (inputs.isEmpty()) { return Collections.emptyList(); } // 并发执行 Collection<ListenableFuture<O>> allFutures = asyncExecute(inputs); // 结果归并 return getResults(allFutures); }
private static <I, O> Collection<ListenableFuture<O>> asyncExecute(final Collection<I> inputs) { Collection<ListenableFuture<O>> result = new ArrayList<>(inputs.size()); for (final I each : inputs) { // 异步执行时直接返回结果 result.add(executorService.submit(() -> (O) each)); } return result; }
private static <O> List<O> getResults(final Collection<ListenableFuture<O>> allFutures) { List<O> result = new LinkedList<>(); for (ListenableFuture<O> each : allFutures) { result.add(each.get()); } return result; }}
总结
跨分片查询的性能这么差,为什么sharding-sphere还要去做呢?笔者认为首先sharding-sphere是一个通用的分库分表中间件,而不是在某些特定条件才能使用的中间件,所以应该要尽可能的兼容所有SQL。其次,即使跨分片查询性能这么差,这个主要是在OLTP系统中使用时要小心,在一些OLAP或者后台管理系统等一些低频次操作的系统中,还是可以使用的。
比如,账户表已经根据账户ID分表,但是在运营操作的后台管理系统中维护账户信息时,肯定有一些操作的SQL是不会带有分片键账户ID的,比如查询账户余额最多的88个土豪用户。这个时候,我们可以通过sharding-sphere中间件直接执行这条低频次SQL。而不需要为了这些操作引入es或者其他组件来解决这种低频次的问题(当然,随着系统的演进,最后可能还是需要引入es等一些中间件来解决这些问题)。所以,分库分表中间件的跨分片查询在项目特定阶段能够大大减少开发成本,从而以最短的时间上线业务需求。
号外:最近整理了之前编写的一系列内容做成了PDF,关注我并回复相应口令获取:
- 001 领取:《Spring Boot基础教程》
- 002 领取:《Spring Cloud基础教程》
更多内容陆续奉上,敬请期待
- END -
近期热文:
别看不起分区表:我要为你点个赞
Spring Cloud Greenwich 正式发布
用认知和人性来做最棒的程序员
Gitlab-CI持续集成的完整实践
在前后端分离的路上承受了多少痛?
你真的会高效的在GitHub上搜索开源项目吗?
中台是个什么鬼?
看完,赶紧点个“好看”鸭
点鸭点鸭
↓↓↓↓
为什么分库分表后不建议跨分片查询相关推荐
- mysql pdo 插入没效果_MySQL分库分表后用PHP如何来完美操作
当单表达到几千万时,查询一次要很久,如果有联合查询,有可能会死在那 分库分表主要就是解决这个问题,减小数据库的负担,缩短查询时间分库 1)按功能分 用户类库.商品类库.订单类库.日志类.统计类库... ...
- 数据库分库分表后,如何部署上线?
1. 引言 我们先来讲一个段子 面试官:"有并发的经验没?" 应聘者:"有一点." 面试官:"那你们为了处理并发,做了哪些优化?" 应聘者: ...
- mysql分表后怎么索引_分库分表后的索引问题
摘要 最近遇到一个慢sql,在排查过程中发现和分库分表后的索引设置有关系,总结了下问题. 问题 在进行应用健康度盘点时,发现有个慢sql 如下 select brandgoodid from bran ...
- mysql 分库分表 后怎么操作,MySQL要分表分库怎么进行数据切分?
导读:关系型数据库本身比较容易成为系统瓶颈,单机存储容量.连接数.处理能力都有限.当单表的数据量达到1000W或100G以后,由于查询维度较多,即使添加从库.优化索引,做很多操作时性能仍下降严重.此时 ...
- 深入理解分布式技术 - 分库分表后的扩容解决方案
文章目录 概述 路由规则与扩容方案 对主键进行哈希取模 优点 缺点 基于数据范围进行拆分 结合数据范围和哈希取模 小结 概述 在实际开发中,数据库的扩容和不同的分库分表规则直接相关,今天我们从系统设计 ...
- mysql为什么表大了要重建_为什么MySQL分库分表后总存储大小变大了?
[MySQL系列相关] 1.聊一聊关于MySQL的count(*) 1.背景 在完成一个分表项目后,发现分表的数据迁移后,新库所需的存储容量远大于原本两张表的大小.在做了一番查询了解后,完成了优化. ...
- sharding-jdbc4.1.1 分库分表后 mysql查询优化(count)
sharding jdbc分库分表之后查询优化 背景 需求 研发历程 1.单线程(sharding jdbc 内置查询机制) 2.多线程(sharding jdbc 内置查询机制) 3.sql调整 结 ...
- 数据库水平分库分表后的数据分页查询解决方案
2021-09-04 更: 推荐下自己的个人框架,后面代码都会移植到框架中 链接 2020-10-19 更: 月底不出意外,打算重构了,fabric区块链框架改的差不多了 2020-10-? 更: 谢 ...
- mysql 多维度分表_亿级订单数据分库分表设计方案(满足多维度查询:订单号、用户、商家、渠道)...
根据业务初步预估订单业务量,每天500万的数据.我们将订单数据划分为了2大类型:分别为热数据和冷数据. 热数据:1个月内的订单数据,查询实时性较高; 冷数据:归档订单数据,查询频率不高; 根据实际业务 ...
最新文章
- java中separator_java - File.separator和路径中的斜杠之间的区别
- CNN在Keras中的实践|机器学习你会遇到的“坑”
- mfc获取别的计算机是否在线,VC获取并修改计算机屏幕分辨率(MFC)
- 苹果手机投屏软件_苹果手机怎样投屏到电脑上操作,用什么软件?
- 计算机专业外语英译汉,信科计算机专业英语英译汉
- AJAX 网页保留浏览器前进后退等功能
- 计算机与操作系统发展阶段 深谈:Linux操作系统
- python接口自动化(十七)--Json 数据处理---一次爬坑记(详解)
- ie浏览器中 textarea 不能自动换行
- 国外安全网站信息收集
- 火狐浏览器 附件组件 Xpath 使用
- 关于新APP,从交底书入手
- photoshop ps 替换图片文字
- python爬虫--王者荣耀高清壁纸下载(多线程)
- vue在初始化时给scrollTop设置一个值,但scrollTop却始终为0
- 脸部转正!GAN能否让侧颜杀手、小猪佩奇真容无处遁形?
- 扎心了!互联网公司福利缩水指南
- 执行rpm -Uvh xxxxxx.rpm, 报freely redistributed under the terms of the GNU GPL
- 零死角玩转Android6.0系统Healthd深入分析
- ld: warning: The i386 architecture is deprecated for macOS (remove from the Xcode build setting: ARC
热门文章
- linux flatpak 简介 同一个应用在不同linux发行版运行
- linux 交叉编译 生成模块 makefile
- linux c glob使用(文件路径模式查找函数)
- mysql utf8 和 utf8mb4 区别
- SpiderMonkey-让你的C++程序支持JavaScript脚本
- 数开头的成语有哪些_艺术留学文书申请过程中应避开哪些雷区?ACG艺术留学
- 专题 4 通用函数库之调试功能封装
- 利用单调栈判断二叉搜索树的后序遍历序列
- spring_了解Spring Web应用程序体系结构:经典方法
- linux selenium_每天进步一点点 selenium+python