暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

基于 OceanBase 列存与物化视图的数仓探索 | 优秀征文分享

OceanBase 2025-01-21
315

“让技术被看见 | OceanBase 布道师计划”是由 OceanBase 主办,墨天轮、ITPUB、CSDN 三大技术媒体协办,面向广大开发者的年度征文活动。全年 4 轮,以季度为周期进行优秀文章评比,每年 1 届,以年为单位进行最佳布道师评选。目前,首轮技术征文获奖文章已评选出炉。


本篇内容为「OceanBase 布道师计划」优秀文章之一,作者 多明戈教你玩狼人杀。布道师计划全年不停歇,欢迎感兴趣的小伙伴点击「阅读原文」进入活动官网,了解活动详情或进一步投稿。🥳


OceanBase 从 4.3 版本开始,同时支持行存和列存,以及可刷新物化视图。这些特性给予了产品更多的使用场景和可能性。过去一年时间里,作为和数仓打交道的人,我最近也做了一些基于这两个特性的测试和探索。现阶段的 OceanBase,已经可以通过这些特性,来实现流和批两种场景下的数仓建设。



1、行存与列存


我们所熟悉的几款数据库产品,都是基于行存的。无论是 MySQL 的 Innodb 引擎,还是 Oracle 原生的存储引擎。在我刚入行的日子里,甚至没有想过世界上还需要有列存引擎的数据库。然而随着数据量的提升,以及大规模报表的查询越来越复杂,同一套硬件设备在数据量增大以后,数据库的查询性能不断下滑。


然而列存恰恰解决了这个问题,如果说行存是为事务而生,那么列存适合于读取部分列数据的场景,尤其是当查询只需要少数几列时,列存的优势就显现出来了。


还有一点,就是列存的压缩比更高,在面对更大数量级的业务数据,带来的成本优势也更高。过往行存依赖的高性能存储,在列存用普通存储亦可。某种程度上来说,列存为数仓而生也不为过。


OceanBase 在 4.3 版本发布的列存,并不能简单称之为列存,而是一体化的行存和列存数据存储,在同一个架构、同一个数据库上实现了列存和行存数据存储一体化,兼顾了事务处理(TP)和分析处理(AP)的查询性能。这个特性在发布会上,让我眼前一亮,也让我这几个月一直在思索如何将这一特性应用到当下的工作和测试过程中。


2、物化视图与表


最早使用物化视图的主流数据库是 Oracle,物化视图与普通视图本质差异在于,物化视图存储了查询结果的数据副本,而且是物理层面的保存,这让复杂查询的结果可以快速地被访问。一直到今天的 Oracle 23ai,物化视图一直在迭代发展。


而现在 OceanBase 的 4.3.3 版本中,物化视图的功能也有了长足进步。有人会问,既然有列存了,还需要有物化视图吗?或者说,物化视图和列存表,各自的优势是什么,彼此适合的场景有什么异同?


这个问题我也很好奇。答案要回到存储引擎本身:LSM-Tree。


OceanBase 基于 LSM-Tree 存储引擎,列存表可以支持事务,可以实现流式写入并且还能确保 ACID,适合做实时数仓。分布式数据库所具备的并行查询,结合 OceanBase的多副本能力,在执行效率上也更加优异。在数仓这种读多写少的场景下,尤其是某些大宽表,大部分时间里只会读取其中一部分列数据的场景下,列存带来的优势很明显。


物化视图通过自身的刷新机制,更适合做一些汇总、分发、多表连接,将一些常用查询的结果落盘。相比较列式存储,物化视图的定期刷新机制,更适合于批量计算的场景。这种计算通常对时间要求不如流式计算那么严格,但需要高效地处理大规模数据集,有时候还承担了一些 ETL 的任务。



1、实时数仓的需求


顾名思义,相较于传统的离线数仓,实时数仓最重要的特点就是实时性。以往的数仓建设,都是 T+1 的数据时效性。对于一些需要实时计算并且获取结果的指标来说,显得不够灵活。而且加入数仓逻辑出现问题,往往在第二天才能发现,重新调整跑任务,都受到时间限制。而在一个企业里,有大量需要实时计算的业务指标,并需要尽可能实时完成计算反馈给相关部门。


所以想建立一个实时数仓,往往需求满足如下的技术:


高性能:想要做到高实时性,性能是先决条件。一个能够用来做实时数仓的产品,性能都不会差。需要数据处理延迟极低,通常在毫秒级到秒级之间,确保数据处理的时效性。


✅ 数据集成:数仓的上游是各种生产系统的数据库甚至是离线数据文件,对实时数仓的产品数据集成丰富度要求很高,要有丰富的数据接口,满足多样化要求。


✅ 可扩展性:实时数仓,除了数据的实时要求,还有一个隐性需求,就是可扩展性的实时。离线数仓往往是夜间跑批,扩展性要求没那么高,但是实时数仓一旦资源出现瓶颈,不能灵活扩容,实时性也就成了空谈。


✅ 安全性:实时性提升对安全也有了更高要求。涉及到实时计算的内容,往往也是关键数据,对数据的安全性和隐私性的要求更高,必须采用多种安全措施,如数据加密、访问控制等,确保数据安全。


✅ 灵活的查询与分析:实时数仓的场景是多元化的,要求数据库产品要能提供丰富的查询和分析工具,支持复杂的查询语句和数据分析模型,否则实时性就会失去的本来的意义。


2、OceanBase 的技术现状


实时性:OceanBase 4.3 版本具备 T+0 的实时写入能力,支持快速的数据导入,能够有效消除数据导入延迟,满足实时分析的需求。


✅ 高性能:4.3 版本引入列式存储引擎和向量化引擎,可以显著提升查询性能,尤其在大宽表场景下,根据我的实际测试,查询性能达到了业内主流列存大宽表数据库的水平,能够实现秒级实时分析。但是,OceanBase 同时支持事务处理,这也会带来额外的性能开销,在这样情况下,列存仍然能够提供足够的性能。


✅ 数据集成:目前为止,OceanBase 4.3 以上的版本,集成了 MySQL 和 Oracle 的各种数据接入方式,其他主流的开源数据库,如 PostgreSQL、Clickhosue 等也可以通过 Flink 生态的工具实现。再加上旁路导入特性进一步加强,OceanBase 已经具备了作为实时数仓的集成能力。


✅ 可扩展性:云原生分布式架构先天支持高并发的读写操作,能够根据业务需求进行水平扩展,适应不断增长的数据量和用户请求。在线扩容副本或者 OBServer 的能力都已经具备,而且根据我的实际测试,OceanBase 能够实现分钟级别的水平扩展。当然,随着数据量和业务量规模,这个数字会不断下降。


✅ 安全性:截止 4.3.3 版本,OceanBase 在安全方面实现的特性包括多租户的资源与权限隔离、数据库安全审计、数据的存储加密和传输加密、基于网络的访问控制、密码复杂度等多种手段,这些特性也让 OceanBase 通过等保三级,这些都是安全性的有力验证。


✅ 灵活查询与分析:目前 OceanBase 支持的数据类型涵盖了大部分常用类型,4.3.3 版本还支持 ARRAY 类型。优化器支持  RBO 与 CBO 两种模式,加上全文索引、向量检索等功能,结合列存与物化视图,我个人认为符合灵活查询与分析的功能需求点。


3、一个实时数仓的 Demo


我们来做一个 Demo,来演示一下列存用于实时数仓的场景。


数据源 1:MySQL 8
数据源 2:PostgreSQL 14
实时数仓:OceanBase 4.3.3 社区版
数据同步:Flink CDC


1️⃣ 创建 MySQL 表并插入数据


    CREATE TABLE orders (
    order_id INT AUTO_INCREMENT,
    order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    customer_name VARCHAR(100),
    price DECIMAL(10, 2),
    product_id INT,
    order_status BOOLEAN,
    PRIMARY KEY (order_id)
    );


    INSERT INTO orders (customer_name, price, product_id, order_status) VALUES
    ('Alice', 19.99, 101, TRUE),
    ('Bob', 29.99, 102, FALSE),
    ('Charlie', 39.99, 103, TRUE),
    ('David'49.99104TRUE);


    2️⃣ 在FlinkCDC 创建表用于读取 MySQL 表。


      CREATE TABLE mysql_source (
      order_id INT,
      order_date TIMESTAMP(0),
      customer_name STRING,
      price DECIMAL(10, 5),
      product_id INT,
      order_status BOOLEAN,
      PRIMARY KEY (order_id) NOT ENFORCED
      ) WITH (
      'connector' = 'mysql-cdc',
      'hostname' = '192.16.1.10',
      'port' = '3306',
      'username' = 'test',
      'password' = 'password',
      'database-name' = 'test',
      'table-name' = 'orders'
      );


      3️⃣ 创建一张 PostgreSQL 表,插入数据。


        CREATE TABLE products (
        product_id INT PRIMARY KEY,
        product_name VARCHAR(100),
        product_description TEXT
        );


        INSERT INTO products (product_id, product_name, product_description) VALUES
        (101, 'Laptop', 'High performance laptop'),
        (102, 'Smartphone', 'Latest model smartphone'),
        (103, 'Tablet', 'Portable and lightweight tablet'),
        (104'Headphones''Noise-cancelling headphones');


        4️⃣ 创建 FlinkcCDC 的 PG 同步表。


          CREATE TABLE postgres_source (
          product_id INT,
          product_name STRING,
          product_description STRING,
          PRIMARY KEY (product_id) NOT ENFORCED
          ) WITH (
          'connector' = 'postgres-cdc',
          'hostname' = '192.168.10。11',
          'port' = '5432',
          'username' = 'test',
          'password' = 'password',
          'database-name' = 'test',
          'schema-name' = 'public',
          'table-name' = 'products'
          );


          5️⃣ 创建 OceanBase 的目标表,使用列存。


            CREATE TABLE joined_orders (
            order_id INT,
            order_date TIMESTAMP,
            customer_name VARCHAR(100),
            price DECIMAL(10, 2),
            product_name VARCHAR(100),
            product_description TEXT,
            order_status BOOLEAN,
            PRIMARY KEY (order_id)
            WITH COLUMN GROUP (each column);


            6️⃣ 根据 OceanBase 目标表的字段,在 Flink 中创建 Join 视图。


              CREATE VIEW joined_orders AS
              SELECT
              o.order_id,
              o.order_date,
              o.customer_name,
              o.price,
              p.product_name,
              p.product_description,
              o.order_status
              FROM mysql_source AS o
              JOIN postgres_source AS p ON o.product_id = p.product_id;


              7️⃣ 配置 FlinkCDC 的写入任务


              具体步骤略(不是我配的)。


              8️⃣ 验证结果。


              如果前面的步骤都顺利完成,那么此时我们查询会有如下结果:


                SELECT * FROM joined_orders;
                +----------+---------------------+---------------+-------+--------------+---------------------------------+--------------+
                | order_id | order_date | customer_name | price | product_name | product_description | order_status |
                +----------+---------------------+---------------+-------+--------------+---------------------------------+--------------+
                | 1 | 2024-11-19 00:00:00 | Alice | 19.99 | Laptop | High performance laptop | 1 |
                | 2 | 2024-11-19 00:00:01 | Bob | 29.99 | Smartphone | Latest model smartphone | 0 |
                | 3 | 2024-11-19 00:00:02 | Charlie | 39.99 | Tablet | Portable and lightweight tablet | 1 |
                | 4 | 2024-11-19 00:00:03 | David | 49.99 | Headphones | Noise-cancelling headphones | 1 |
                +----------+---------------------+---------------+-------+--------------+---------------------------------+--------------+


                在源表插入数据:


                  INSERT INTO orders (customer_name, price, product_id, order_status) VALUES ('Eve'59.99105TRUE);
                  ---- MySQL表


                  INSERT INTO products (product_id, product_name, product_description) VALUES (105'Smartwatch''Advanced smartwatch with health tracking features'); ----PG表


                  两边提交之后,实时查询 OceanBase 表,能够实时得到新结果:


                    SELECT * FROM joined_orders;


                    +----------+---------------------+---------------+-------+--------------+---------------------------------------------------+--------------+
                    | order_id | order_date | customer_name | price | product_name | product_description | order_status |
                    +----------+---------------------+---------------+-------+--------------+---------------------------------------------------+--------------+
                    | 1 | 2024-11-19 00:00:00 | Alice | 19.99 | Laptop | High performance laptop | 1 |
                    | 2 | 2024-11-19 00:00:01 | Bob | 29.99 | Smartphone | Latest model smartphone | 0 |
                    | 3 | 2024-11-19 00:00:02 | Charlie | 39.99 | Tablet | Portable and lightweight tablet | 1 |
                    | 4 | 2024-11-19 00:00:03 | David | 49.99 | Headphones | Noise-cancelling headphones | 1 |
                    | 5 | 2024-11-19 00:00:05 | Eve | 59.99 | Smartwatch | Advanced smartwatch with health tracking features | 1 |
                    +----------+---------------------+---------------+-------+--------------+---------------------------------------------------+--------------+


                    4、小结


                    Demo 并不复杂,就是简单的两张表 Join 最后吐出结果。主要为了验证实时性。结合 OceanBase 列存的性能以及多副本读写分离,这实际就是一个极简版的实时数仓。可以看到,OceanBase 在 FlinkCDC 作为工具的情况下,能够实现秒级别的实时数仓功能。


                    当然,这个 Demo 由于资源和时间所限,没有能够模拟更大数据量和更复杂的计算,只是作为一个参考,如果以后有机会,我会补充一个更详尽版的 Demo。



                    1、批处理数仓的技术需求


                    批处理数仓,其实就是我们常说的传统数仓。这种类型的数仓主要依赖于批量数据处理技术,通常在每天的特定时间运行 ETL,将数据从源系统提取出来,进行转换和清洗,然后加载到数据仓库中。实时性要求不高,但是却对产品有其他的要求:


                    ① 存储能力:


                    因为需要保存更多的历史数据,批处理数仓的数据量更大,而且需要更高的数据吞吐量能力,每天晚上的批处理包含的数据量远高于实时数仓的实时写入。而且数据量大的时候,对于数据压缩的需求也更加迫切。


                    ② 数据处理能力:


                    这里的处理能力比起实时数仓要求就更广泛。除了常用的对象类型和 SQL 支持,还需要考虑大规模数据并行计算的能力,有可能每天计算量超过百 GB。在各类复杂报表中,还需要考虑索引加速等手段,尽可能提高性能。


                    ③ 数据一致性:


                    在多个复杂 ETL 过程中,往往需要事务的支持,从加载到转换再到计算落盘。一致性往往还需要通过一些约束来辅佐,比如主键、唯一键、非空键等等,用来确保一致性和数据质量。


                    ④ 安全性、数据集成:


                    理由基本同实时数仓。


                    2、OceanBase 的现状


                    ① 存储能力:


                    目前从各类客户案例以及我自己导入的百 GB 级别(再多测试资源就不够了),能够提供更高的数据吞吐量和存储能力,满足批处理数仓对大数据量存储的需求。同时,列存可以实现性能最优和最小的存储空间,对数据压缩有较好的支持,能够应对数据量大时对数据压缩的需求。


                    ② 数据处理能力:


                    OceanBase 在 4.3 版本推出基于 Column 数据格式的 2.0 向量化引擎,是一个能够显著提升 AP 场景查询性能的特性。这使得 OceanBase 具备大规模数据并行计算的能力,能够处理每天计算量超过百 GB 的需求。在分配足够多资源的情况下,这些都不是问题。物化视图功能,通过预计算存储视图的查询结果提升实时查询性能,这对于提高复杂报表中的查询性能是一个大杀器。


                    ③ 数据一致性:


                    如同之前所说的,OceanBase 事务处理能力,能够满足多个复杂 ETL 过程中对事务的需求。在数据加载、转换和计算落盘的过程中,能够保证数据的一致性。而主键、唯一键、非空键等约束,无论是行存还是列存,都是一视同仁支持的,这也打消了我对数据一致性的顾虑。


                    ④ 安全性、数据集成:


                    现状基本同实时数仓。


                    3、基于物化视图的探索


                    我们本次对批处理数仓的探索,主要基于 OceanBase 的物化视图。我们模拟一个批处理数仓的场景,来验证物化视图对数据查询的加速。


                    测试数据:TPCH,10G/20G

                    测试语句:多表查询与物化视图直查

                    测试版本:OceanBase 4.3.3 社区版


                    1️⃣ 创建 TPC-H 数据表


                    根据 TPC-H 要求,创建 8 张表,全部使用列存。


                      CREATE TABLE NATION  ( N_NATIONKEY  INTEGER NOT NULL,
                      N_NAME VARCHAR(25) NOT NULL,
                      N_REGIONKEY INTEGER NOT NULL,
                      N_COMMENT VARCHAR(152),
                      PRIMARY KEY (N_NATIONKEY)
                      )WITH COLUMN GROUP (each column);


                      CREATE TABLE REGION ( R_REGIONKEY INTEGER NOT NULL,
                      R_NAME VARCHAR(25) NOT NULL,
                      R_COMMENT VARCHAR(152),
                      PRIMARY KEY (R_REGIONKEY)
                      )WITH COLUMN GROUP (each column);


                      CREATE TABLE PART ( P_PARTKEY INTEGER NOT NULL,
                      P_NAME VARCHAR(55) NOT NULL,
                      P_MFGR VARCHAR(25) NOT NULL,
                      P_BRAND VARCHAR(10) NOT NULL,
                      P_TYPE VARCHAR(25) NOT NULL,
                      P_SIZE INTEGER NOT NULL,
                      P_CONTAINER VARCHAR(10) /*CHAR(10)*/ NOT NULL,
                      P_RETAILPRICE DECIMAL(15,2) NOT NULL,
                      P_COMMENT VARCHAR(23) NOT NULL,
                      PRIMARY KEY (P_PARTKEY)
                      )WITH COLUMN GROUP (each column);


                      CREATE TABLE SUPPLIER ( S_SUPPKEY INTEGER NOT NULL,
                      S_NAME VARCHAR(25) NOT NULL,
                      S_ADDRESS VARCHAR(40) NOT NULL,
                      S_NATIONKEY INTEGER NOT NULL,
                      S_PHONE VARCHAR(15) NOT NULL,
                      S_ACCTBAL DECIMAL(15,2) NOT NULL,
                      S_COMMENT VARCHAR(101) NOT NULL,
                      PRIMARY KEY (S_SUPPKEY)
                      )WITH COLUMN GROUP (each column);


                      CREATE TABLE PARTSUPP ( PS_PARTKEY INTEGER NOT NULL,
                      PS_SUPPKEY INTEGER NOT NULL,
                      PS_AVAILQTY INTEGER NOT NULL,
                      PS_SUPPLYCOST DECIMAL(15,2) NOT NULL,
                      PS_COMMENT VARCHAR(199) NOT NULL,
                      PRIMARY KEY (PS_PARTKEY, PS_SUPPKEY)
                      )WITH COLUMN GROUP (each column);


                      CREATE TABLE CUSTOMER ( C_CUSTKEY INTEGER NOT NULL,
                      C_NAME VARCHAR(25) NOT NULL,
                      C_ADDRESS VARCHAR(40) NOT NULL,
                      C_NATIONKEY INTEGER NOT NULL,
                      C_PHONE VARCHAR(15) NOT NULL,
                      C_ACCTBAL DECIMAL(15,2) NOT NULL,
                      C_MKTSEGMENT VARCHAR(10) NOT NULL,
                      C_COMMENT VARCHAR(117) NOT NULL,
                      PRIMARY KEY (C_CUSTKEY)
                      )WITH COLUMN GROUP (each column);


                      CREATE TABLE ORDERS ( O_ORDERKEY BIGINT NOT NULL,
                      O_CUSTKEY INTEGER NOT NULL,
                      O_ORDERSTATUS VARCHAR(1) NOT NULL,
                      O_TOTALPRICE DECIMAL(15,2) NOT NULL,
                      O_ORDERDATE DATE NOT NULL,
                      O_ORDERPRIORITY VARCHAR(15) NOT NULL,
                      O_CLERK VARCHAR(15) NOT NULL,
                      O_SHIPPRIORITY INTEGER NOT NULL,
                      O_COMMENT VARCHAR(79) NOT NULL,
                      PRIMARY KEY (O_ORDERKEY)
                      )WITH COLUMN GROUP (each column);


                      CREATE TABLE LINEITEM ( L_ORDERKEY BIGINT NOT NULL,
                      L_PARTKEY INTEGER NOT NULL,
                      L_SUPPKEY INTEGER NOT NULL,
                      L_LINENUMBER INTEGER NOT NULL,
                      L_QUANTITY INTEGER NOT NULL,
                      L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL,
                      L_DISCOUNT DECIMAL(15,2) NOT NULL,
                      L_TAX DECIMAL(15,2) NOT NULL,
                      L_RETURNFLAG VARCHAR(1) NOT NULL,
                      L_LINESTATUS VARCHAR(1) NOT NULL,
                      L_SHIPDATE DATE NOT NULL,
                      L_COMMITDATE DATE NOT NULL,
                      L_RECEIPTDATE DATE NOT NULL,
                      L_SHIPINSTRUCT VARCHAR(25) NOT NULL,
                      L_SHIPMODE VARCHAR(10) NOT NULL,
                      L_COMMENT VARCHAR(44) NOT NULL,
                      PRIMARY KEY (L_ORDERKEY, L_LINENUMBER)
                                              )WITH COLUMN GROUP (each column);


                      2️⃣ 使用数据生成工具,生成份 10GB 大小的数据集。


                        ./dbgen -s 10


                        3️⃣ 导入其中一份 10GB 数据,导入前请检查是否已经配置过 secure_file_priv。


                          SET SESSION ob_query_timeout = 1000000000000
                          LOAD DATA INFILE '/tmp/tpch-dbgen-master/part.tbl' INTO TABLE part FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';
                          LOAD DATA INFILE '/tmp/tpch-dbgen-master/nation.tbl' INTO TABLE nation FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';
                          LOAD DATA INFILE '/tmp/tpch-dbgen-master/region.tbl' INTO TABLE region FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';
                          LOAD DATA INFILE '/tmp/tpch-dbgen-master/supplier.tbl' INTO TABLE supplier FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';
                          LOAD DATA INFILE '/tmp/tpch-dbgen-master/partsupp.tbl' INTO TABLE partsupp FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';
                          LOAD DATA INFILE '/tmp/tpch-dbgen-master/customer.tbl' INTO TABLE customer FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';
                          LOAD DATA INFILE '/tmp/tpch-dbgen-master/orders.tbl' INTO TABLE orders FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';
                          LOAD DATA INFILE '/tmp/tpch-dbgen-master/lineitem.tbl' INTO TABLE lineitem FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';


                          4️⃣ 随即执行一条 TPC-H,我选择了 Q11,记录执行时间 3.33 秒。


                            select
                            ps_partkey,
                            sum(ps_supplycost * ps_availqty) as value
                            from
                            partsupp,
                            supplier,
                            nation
                            where
                            ps_suppkey = s_suppkey
                            and s_nationkey = n_nationkey
                            and n_name = 'GERMANY'
                            group by
                            ps_partkey having
                            sum(ps_supplycost * ps_availqty) > (
                            select
                            sum(ps_supplycost * ps_availqty) * 0.000002
                            from
                            partsupp,
                            supplier,
                            nation
                            where
                            ps_suppkey = s_suppkey
                            and s_nationkey = n_nationkey
                            and n_name = 'GERMANY'
                            )
                            order by
                                value desc;


                            5️⃣ 根据 Q11,创建物化视图。


                              CREATE MATERIALIZED VIEW mv_q11
                              REFRESH COMPLETE ON DEMAND
                              AS
                              select
                              ps_partkey,
                              sum(ps_supplycost * ps_availqty) as value
                              from
                              partsupp,
                              supplier,
                              nation
                              where
                              ps_suppkey = s_suppkey
                              and s_nationkey = n_nationkey
                              and n_name = 'GERMANY'
                              group by
                              ps_partkey having
                              sum(ps_supplycost * ps_availqty) > (
                              select
                              sum(ps_supplycost * ps_availqty) * 0.000002
                              from
                              partsupp,
                              supplier,
                              nation
                              where
                              ps_suppkey = s_suppkey
                              and s_nationkey = n_nationkey
                              and n_name = 'GERMANY'
                              )
                              order by
                                  value desc;


                              6️⃣ 清理缓存后查询该物化视图,获取时间 0.46 秒,提升了 7 倍的性能。


                                select * from mv_q11;


                                而且随着数据量的增多,物化视图带来的性能增益将会更加明显。比如生产环境的系统,每天如果增加几十 GB 的数据量,采用 OceanBase 物化视图的增量刷新,实际效果会更好,比如这里就是 6 个小时刷新一次。


                                  CREATE MATERIALIZED VIEW mv_q11
                                  REFRESH FORCE
                                  START WITH SYSDATE
                                  NEXT SYSDATE + 6/24
                                  AS
                                  select
                                  ps_partkey,
                                  sum(ps_supplycost * ps_availqty) as value
                                  from
                                  partsupp,
                                  supplier,
                                  nation
                                  where
                                  ps_suppkey = s_suppkey
                                  and s_nationkey = n_nationkey
                                  and n_name = 'GERMANY'
                                  group by
                                  ps_partkey having
                                  sum(ps_supplycost * ps_availqty) > (
                                  select
                                  sum(ps_supplycost * ps_availqty) * 0.000002
                                  from
                                  partsupp,
                                  supplier,
                                  nation
                                  where
                                  ps_suppkey = s_suppkey
                                  and s_nationkey = n_nationkey
                                  and n_name = 'GERMANY'
                                  )
                                  order by
                                      value desc;


                                  4、小结


                                  可以看到的是,即便是基于列存的表,查询效率比起落盘后的物化视图,仍然有着不小的时间差。而在很多数仓中,我们都会遇到一些常用且数据量很大的固定查询或者报表等,如果能够使用物化视图,每天定期刷新,可以大幅减少系统开销。


                                  实际上,物化视图不过是数仓最后一个层级,即我们平时提比较多的数据集市层或者报表层,下面还有汇总层、基础层、ODS 层等等,其实都可以通过批量 ETL 转换成 OceanBase 列存表,大大提高以往用行存的性能,而最上面的一层,则使用物化视图来实现。



                                  依靠行存和 TP 起家的 OceanBase,在列存上的发力让我多少有些意外之喜,尤其是实际验证了行存列存的性能差距之后。这套列存技术非常适用于数仓。在列存模式下,底层存储的每列数据存储为一个独立的 SSTable,所有列的 SSTable 组合成为一个虚拟 SSTable 作为用户的列存基线数据。这种设计使得列存表数据可以像行存表一样进行所有事务操作,既可以提高性能,又可以提高压缩率。在未来也许还会有更多的新特性,用于增强。


                                  而在批处理数仓中,OceanBase 的物化视图可以把复杂的查询预处理后,将计算结果存储起来,从而加快查询速度。一定程度上减少了对外部 ETL 的依赖。本文没有涉及到的是,OceanBase 的物化视图支持灵活的刷新策略,包括全量刷新和按需刷新,可以根据业务需求选择合适的刷新模式。使用过程中,性能也非常稳定,这一点上在国产数据的表现非常突出。我用过的物化视图也有不少,但是性能和便捷性上参差不齐。


                                  有关从 ODS 到 DWD 再到 DWS,以及最后的应用层该如何构建,其实也是足以写一篇几千字文章的内容。这部分在新的列存引擎面前,可以大大提高效率,只是囿于篇幅所限,以及我本人精力的限制,只能写到这里。实际上在我的测试环境中,已经将这几层的测试数据都搬到了 OceanBase 的列存表中,也做了很多测试。过去要用小时计算的 ETL 任务,在列存的加速下,性能提升可以翻倍起步。这中间很多计算逻辑并没有根据列存做过调整,认真优化的话,只会更快。






                                  评委有话说


                                  资深 IT 媒体人、《老鱼笔记》主理人老鱼:文章探讨了 OceanBase 4.3 版本中引入的列存和物化视图特性在数据仓库建设中的应用,展示了这些新特性如何显著提升查询性能和降低系统开销。文中不仅提供了详尽的技术背景、特性对比及实际操作步骤,还通过具体案例(如 TPC-H 测试)验证了性能增益,体现了理论与实践的紧密结合。


                                  CSDN 资讯主编、《新程序员》特约专栏记者屠敏:本文深入探讨了 OceanBase 的列存和物化视图特性,结合实时与批处理数仓场景,展示了其技术优势。文章逻辑清晰,通过实际案例和代码示例,体现了 OceanBase 在提升查询性能和降低成本方面的巨大价值,为数仓领域的从业者提供了一定的实践指导。


                                  2025 OceanBase 布道师计划
                                  期待你的分享 ❤❤❤



                                  往期推荐

                                   点击「阅读原文」,了解详情,立即投稿

                                  文章转载自OceanBase,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                  评论