前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为什么分库分表后不建议跨分片查询

为什么分库分表后不建议跨分片查询

作者头像
程序猿DD
发布2019-03-08 12:18:14
1.7K0
发布2019-03-08 12:18:14
举报
文章被收录于专栏:程序猿DD程序猿DD

来源:阿飞的博客

在这篇文章中提到了一个场景,即电商的订单。我们都知道订单表有三大主要查询:基于订单ID查询基于商户编号查询基于用户ID查询。且那篇文章给出的方案是基于订单ID、商户编号、用户ID都有一份分库分表的数据。那么为什么要这么做?能否只基于某一列例如用户ID分库分表,答案肯定是不能。

笔者基于sharding-sphere(GitHub地址:https://github.com/apache/incubator-shardingsphere)进行了一个简单的测试,测试环境如下:

  1. 128个分表:image_${0..127};
  2. 数据库服务器:32C64G;
  3. 数据库版本:MySQL-5.7.23;
  4. 操作系统:CentOS 6.9 Final;
  5. 连接池:druid 1.1.6;
  6. mysql-connector-java:6.0.5;
  7. mybatis:3.4.5;
  8. mybatis-spring:1.3.1;
  9. springboot:1.5.9.RELEASE;
  10. sharding-sphere-3.1.0;
  11. JVM参数:-Xmx2g -Xms2g -Xmn1g -Xss256k -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+AlwaysPreTouch;
  12. druid配置:默认参数;

表信息如下:

代码语言:javascript
复制
-- id是分片键。备注,DDL是伪SQL
CREATE 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)查询;

测试结果如下:

分片键PK.跨分片键

结论:由测试结果可知,跨分片查询相比带分片键查询的性能衰减了很多。

第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。其结果如下:

Multi-Thread Executor Test

结论:由这个测试结果可知,当并发执行越来越多,其结果归并的代价越来越大。

附--空跑sharding-sphere依赖的并发执行组件google-guava的MoreExecutors的部分源码如下:

代码语言:javascript
复制
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等一些中间件来解决这些问题)。所以,分库分表中间件的跨分片查询在项目特定阶段能够大大减少开发成本,从而以最短的时间上线业务需求

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-02-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序猿DD 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 来源:阿飞的博客
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档