如何提升AnalyticDB实时写入性能

本文涉及的产品
阿里云百炼推荐规格 ADB PostgreSQL,4核16GB 100GB 1个月
云原生数据仓库AnalyticDB MySQL版,基础版 8ACU 100GB 1个月
简介: 从AnalyticDB写入原理分析,可以从三个方面提升AnalyticDB的写入能力:降低网络传输开销、减少与硬件设备io操作和尽量少消耗cpu资源。针对这三个特性本文将介绍如何对写入sql进行改造以达到最优性能。

从AnalyticDB写入原理分析,可以从三个方面提升AnalyticDB的写入能力:降低网络传输开销、减少与硬件设备io操作和尽量少消耗cpu资源。针对这三个特性本文将介绍如何对写入sql进行改造以达到最优性能。

  • 采用批量写入(batch insert)模式,即每次在VALUES部分添加多行数据,一般建议每次批量写入数据量大约为16KB,以提高网络和磁盘吞吐。如下
INSERT INTO db_name.table_name (col1, col2, col3) VALUES ('xxx', 111, 'xxx'), ('xxx', 222, 'xxx'), ('xxx', 333, 'xxx');
  • 如果对一行的所有列都进行插入,则去除col_name并保证values顺序与表结构中的col_name顺序一致,以降低网络带宽耗用。如下
INSERT INTO db_name.table_name VALUES ('xxx', 111, 'xxx'), ('xxx', 222, 'xxx'), ('xxx', 333, 'xxx');
  • 保持主键相对有序。AnalyticDB的insert语句要求必须提供主键,且主键可以为复合主键。当确定复合主键时,根据业务含义调整复合主键中各个列的次序,从业务层面保证插入时主键是严格递增或近似递增的,也可以提升实时写入速度。
  • 增加ignore关键字。执行不带ignore关键字的insert sql,当主键冲突时,后续数据会覆盖之前插入的数据;带上ignore关键字,则主键冲突时,会保留之前插入的数据而自动忽略新数据。如果业务层没有数据覆盖的语义要求,则建议所有insert sql都加上ignore关键字,以减小覆盖数据带来的性能开销。
  • AnalyticDB需要对数据进行分区存储,当一次Batch insert中含有属于不同分区的多行数据时,将会耗费大量CPU资源进行分区号计算。因此建议在写入程序中提前计算好每行数据的分区号,并且将属于同一分区的多行数据组成一个批次,一次性插入。

实现聚合写入目前主要有两种途径:

  • 用户自行实现该聚合方法,对分区号的计算规则为:partition_num = CRC32(hash_partition_column_value) mod m,其中hash_partition_column_value是分区列的值,m是分区总数。如下代码
public class HashInsert extends AbstractJavaSamplerClient{
    private static Logger log = Logger.getLogger(HashInsert1M.class.getName());
    private static AtomicLong idGen = new AtomicLong();
    private int bufferSize =2000 
    private int batchSize = 20;
    private int partitionCnt = 100;

    public SampleResult runTest(JavaSamplerContext arg0) {
        ..........
        ..........
        String sqls[] = new String[bufferSize];
        int partNo[] = new int [bufferSize];
        int sortedSqlIndex[] = new int [bufferSize];
        int end = 100;
        for(int i = 0; i < bufferSize; i++) {
            long id = idGen.getAndIncrement();
            boolean boolean_id = DataUtil.getBoolean_test(id);
            int byte_id = DataUtil.getByte_test(id);
            int short_id = DataUtil.getShort_test(id);
            long user_id = DataUtil.getInt_test(id);
            long seller_id = id;
            float float_id = DataUtil.getFloat_test(id);
            double double_id = DataUtil.getDouble_test(id);
            String follow_id = DataUtil.getString_test(id);
            String time_id = DataUtil.getTime_test(id);
            String date_id = DataUtil.getDate_test(id);
            String timestamp_id = DataUtil.getTimestamp_test(id);
            String interest_flag = DataUtil.getMutilValue(id);
               StringBuffer sb = new StringBuffer();
            sb.append("(").append(boolean_id).append(",").append(byte_id).append(",").append(short_id).append(",").append(user_id)
            .append(",").append(seller_id).append(",").append(float_id).append(",").append(double_id).append(",'").append(follow_id)
            .append("','").append(time_id).append("','").append(date_id).append("','").append(timestamp_id).append("','").append(interest_flag)
            .append("',");
            for(int j=0;j<end-1;j++){
                sb.append("'").append(follow_id).append("',");
            }
            sb.append("'").append(follow_id).append("')");
            sqls[i]  = sb.toString();

            partNo[i] = getHashPartition("" + user_id, partitionCnt);
            sortedSqlIndex[i] = i;
        }

        for(int i = 0; i < bufferSize - 1; i++) {
            for(int j = i + 1; j < bufferSize; j++) {
                if (partNo[sortedSqlIndex[i]] > partNo[sortedSqlIndex[j]]) {
                    int tmp = sortedSqlIndex[i];
                    sortedSqlIndex[i] = sortedSqlIndex[j];
                    sortedSqlIndex[j] = tmp;
                }
            }
        }

        batchSize =  Integer.valueOf(AdsUtil.getBatchNum());
        try {
            .........
            .........
            String dbName = AdsUtil.getDBName();
            String tableName = AdsUtil.getTableName();
            String sql = "insert into " + dbName + "." + tableName  + " values ";
            for(int i = 0; i < bufferSize  - batchSize; i+= batchSize) {
                StringBuffer sb = new StringBuffer(sql);
                for(int j = 0 ; j < batchSize; j++) {
                    if (j != 0)
                        sb.append(",");
                    sb.append(sqls[sortedSqlIndex[i + j]]);                
                }
                ..............
                ..............
            }
            res = true;
        } catch (Exception e) {
            ...........
            ...........
        } finally {
            ...........
            ...........
        }

        return ...;
    }

    public static int getHashPartition(String value, int totalHashPartitionNum) {
        long crc32 = (value == null ? getCRC32("-1") : getCRC32(value));
        return (int) (crc32 % totalHashPartitionNum);
    }

    private static long getCRC32(String value) {
        Checksum checksum = new CRC32();
        byte[] bytes = value.getBytes();
        checksum.update(bytes, 0, bytes.length);
        return checksum.getValue();
    }
}
  • 采用AnalyticDB搭配的同步工具”数据集成”进行实时数据同步。一般建议采用第二种方法。
相关实践学习
AnalyticDB MySQL海量数据秒级分析体验
快速上手AnalyticDB MySQL,玩转SQL开发等功能!本教程介绍如何在AnalyticDB MySQL中,一键加载内置数据集,并基于自动生成的查询脚本,运行复杂查询语句,秒级生成查询结果。
阿里云云原生数据仓库AnalyticDB MySQL版 使用教程
云原生数据仓库AnalyticDB MySQL版是一种支持高并发低延时查询的新一代云原生数据仓库,高度兼容MySQL协议以及SQL:92、SQL:99、SQL:2003标准,可以对海量数据进行即时的多维分析透视和业务探索,快速构建企业云上数据仓库。 了解产品 https://www.aliyun.com/product/ApsaraDB/ads
目录
相关文章
|
关系型数据库 MySQL Linux
ADB MySQL湖仓版在Linux和Windows上的性能差异
ADB MySQL湖仓版在Linux和Windows上的性能差异
122 1
|
4月前
|
存储 运维 Kubernetes
实时数仓Hologres提升问题之调度性能如何解决
Hologres可以支持的最大节点规模是多少?
48 1
|
1月前
|
监控 数据挖掘 OLAP
深入解析:AnalyticDB中的高级查询优化与性能调优
【10月更文挑战第22天】 AnalyticDB(ADB)是阿里云推出的一款实时OLAP数据库服务,它能够处理大规模的数据分析任务,提供亚秒级的查询响应时间。对于已经熟悉AnalyticDB基本操作的用户来说,如何通过查询优化和性能调优来提高数据处理效率,是进一步提升系统性能的关键。本文将从个人的角度出发,结合实际经验,深入探讨AnalyticDB中的高级查询优化与性能调优技巧。
99 4
|
6月前
|
分布式计算 关系型数据库 数据挖掘
实时数仓 Hologres产品使用合集之当使用动态分区管理功能按日期进行分区后,通过主键和segment_key进行时间范围查询性能变差是什么原因
实时数仓Hologres的基本概念和特点:1.一站式实时数仓引擎:Hologres集成了数据仓库、在线分析处理(OLAP)和在线服务(Serving)能力于一体,适合实时数据分析和决策支持场景。2.兼容PostgreSQL协议:Hologres支持标准SQL(兼容PostgreSQL协议和语法),使得迁移和集成变得简单。3.海量数据处理能力:能够处理PB级数据的多维分析和即席查询,支持高并发低延迟查询。4.实时性:支持数据的实时写入、实时更新和实时分析,满足对数据新鲜度要求高的业务场景。5.与大数据生态集成:与MaxCompute、Flink、DataWorks等阿里云产品深度融合,提供离在线
|
1月前
|
SQL 监控 大数据
优化AnalyticDB性能:查询优化与资源管理
【10月更文挑战第25天】在大数据时代,实时分析和处理海量数据的能力成为了企业竞争力的重要组成部分。阿里云的AnalyticDB(ADB)是一款完全托管的实时数据仓库服务,支持PB级数据的秒级查询响应。作为一名已经有一定AnalyticDB使用经验的开发者,我发现通过合理的查询优化和资源管理可以显著提升ADB的性能。本文将从个人角度出发,分享我在实践中积累的经验,帮助读者更好地利用ADB的强大功能。
44 0
|
7月前
|
存储 监控 Cloud Native
如何通过持续测试和调整来提高OLAP系统的性能和可扩展性?
【5月更文挑战第14天】如何通过持续测试和调整来提高OLAP系统的性能和可扩展性?
71 2
|
5月前
|
SQL 弹性计算 测试技术
实时数仓Hologres TPC-H及点查性能开箱测试
Hologres现在仍然是TPCH-30000榜单的全球第一,领先第二名高达23%,最新发布的2.2版本相比之前的1.x的版本性能大约提升100%。
|
7月前
|
存储 安全 数据挖掘
性能30%↑|阿里云AnalyticDB*AMD EPYC,数据分析步入Next Level
第4代 AMD EPYC加持,云原生数仓AnalyticDB分析轻松提速。
性能30%↑|阿里云AnalyticDB*AMD EPYC,数据分析步入Next Level
|
7月前
|
SQL 测试技术 OLAP
现代化实时数仓 SelectDB 再次登顶 ClickBench 全球数据库分析性能排行榜!
现代化实时数仓 SelectDB 在时隔两年后再次完成登顶,在全部近百款数据库和数十种机型中,性能位居总榜第一!
现代化实时数仓 SelectDB 再次登顶 ClickBench 全球数据库分析性能排行榜!
|
6月前
|
存储 缓存 测试技术
现代化实时数仓 SelectDB 再次登顶 ClickBench 全球数据库分析性能排行榜!
近日,在 ClickHouse 发起的分析型数据库性能测试排行榜 ClickBench(https://benchmark.clickhouse.com/)中,现代化实时数仓 SelectDB 时隔两年后再次登顶,在全部近百款数据库和数十种机型中,性能表现位居总榜第一!
192 1

相关产品

  • 云原生数据仓库AnalyticDB MySQL版