ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

SAP HANA复制表实战:从虚拟表到落地副本的完整指南

SAP HANA复制表实战:从虚拟表到落地副本的完整指南 做 SAP HANA 数据集成这几年我见过最多的一种误会就是以为在 HANA 里建了虚拟表就等于把数据拿过来了。业务同事跑过来问为什么我在 HANA 里查表报表还是 20 秒起步一看后台查的根本不是本地表SQL 被推到了远端源执行。真正想解决这类问题你得把远端表变成一份可落地的数据副本这就是 SAP HANA 里经常提到的 Replica Tables。这篇文章我把远端表、虚拟表、复制表的关系讲透再给一套从初始化到刷新的实操路径适合正在做 SAP HANA 数据同步、数仓集成或者刚开始接触 SDA/SDI 的读者。内容不绕弯子直接按实际干活的经验来。1. 先搞清楚虚拟表为什么不够用1.1 虚拟表不只是“连接”而是一条远程执行的 SQL 链很多刚接触 SDASmart Data Access的同学建完 Remote Source 再创建 Virtual Table看到 HANA Catalog 里出现了一张表就以为数据已经在 HANA 里了。这个误解是后面所有性能问题的根源。虚拟表的本质是一段“查询转发规则”。你在 HANA 里执行SELECT * FROM VT_ORDERSHANA 并不会把整张表拉回来而是把这个 SQL 拆解、改写尽量下推给远端的源数据库执行。远端算完后把结果集通过网络传回 HANAHANA 只负责最终展示或者做二次加工。这个过程很像你电脑上放着某个网盘的快捷方式图标看起来像一个文件双击后其实还是从远端拉内容。网盘里的文件如果很大、网络又一般打开速度自然感人。虚拟表也这样它把“计算压力”扔给远端源把“网络压力”留给自己。对几百行的小表问题不大一旦源表几百万行报表查询里又带 JOIN 和 GROUP BY远端源和网络的瓶颈马上暴露出来。还有个容易忽略的点虚拟表能不能在 HANA 端做索引、分区、压缩都不行。因为数据根本不在 HANA 里HANA 只是“代转”SQL 的角色。你给虚拟表建索引系统会直接拒绝想都不要想。1.2 复制表与虚拟表的本质差异存储换性能理解了虚拟表是“快捷方式”那复制表就很好解释了复制表是把远端的数据实际拉下来在 HANA 本地真实落盘存储形成一份独立的、可查询、可建索引、可分区的数据副本。它和虚拟表最大的差异只有一个数据到底放在哪。维度虚拟表复制表/落地副本数据存储位置远端源数据库HANA 本地查询执行位置远端为主HANA 组装结果全部在 HANA 本地实时性接近实时受网络和源端负载影响取决于刷新策略有延迟本地索引/分区/压缩不支持完全支持对远端可用性的依赖每次查询都依赖只在刷新时依赖资源消耗网络带宽、远端 CPU/IOHANA 本地内存和 CPU适用场景小表、低频查询、实时访问大表、分析型查询、高频访问一句话总结复制表是用 HANA 的存储空间换查询性能。副本一旦建好日常查询完全不需要再跑去远端拉数据也不怕源库临时抖动、连接断开甚至在源库维护窗口期报表照样能跑。不过代价也很直白HANA 是内存数据库本地副本会真实占用内存资源同步延迟需要靠刷新频率控制运维上多了一套刷新的监控任务。这也是为什么我标题里强调的是“可落地的数据副本”——落地的意思就是真正放进了 HANA 的内存和磁盘体系里不再是个“虚拟映射”。2. 复制表是怎么工作的什么时候该用2.1 一条数据从远端到本地的完整路径复制表不是凭空出现的它背后是一条清晰的数据链路。用我实际项目里最常见的一条链路来走一遍第一步创建 Remote Source也就是配置远端数据库的连接信息。HANA 通过这个连接去和远端数据库建立会话。第二步在远端 Source 上创建 Virtual Table作为取数的“管道”HANA 要能先“看到”远端表的结构和字段。第三步本地建一张目标表将虚拟表里的数据初始化填入这是副本诞生的关键一步。第四步按照设定的刷新周期把源端新增或变更的数据同步到本地表。第五步业务查询直接打本地表。你注意看整个链路里虚拟表承担的角色很微妙它不是终点而是“取数的中间层”。建复制表的时候实际上还是通过虚拟表去远端取数据只不过取完之后在本地落了地。有人会问能不能直接用一张本地表和远端建复制关系不建虚拟表在我的经验里不建议这样裸操作。虚拟表充当了一个“结构验证器”你能提前确认字段映射、类型转换、访问权限都OK了再决定初始化出问题也好排查。2.2 三种同步刷新方式一次性、定时全量、持续增量讲刷新方式之前先明确一件事复制表默认不会自动更新。你复制一份副本出来它就定格在那一刻后续源表怎么变和它没关系。要让它保持新鲜必须梳理清楚刷新策略。我习惯把刷新方式分成三档第一档是一次性快照。用CREATE TABLE AS SELECT把数据复制过来常用于初始化、测试环境搭建、或者迁移临时数据。它是一次性的跑完就结束不涉及后续任务调度。第二档是定时全量刷新。对增量控制不敏感的小表比如几万到几十万行的维度表就非常合适。每到凌晨或者每小时把目标表清空再重新从虚拟表全量拉一遍。优点是逻辑简单不容易出错缺点是数据量大时耗时较长频繁全量刷新会给源库增加压力。第三档是持续增量同步。源表有明确的更新时间戳并且业务上有新增和修改就可以按时间戳做增量。更复杂的场景比如源表没有时间戳、却有大量 update 操作那就要靠 SAP HANA SDISmart Data Integration的复制任务基于数据库日志做 CDC 捕获把数据变更实时或准实时地同步到 HANA。这三档没有绝对的好坏我的原则是能用增量不轻易做全量能做全量不勉强设计 CDC。增量同步是省资源但设计不好容易漏数据后面第 4 部分我会专门讲这个坑。2.3 怎么判断一张表适不适合落地副本不是什么表都值得做成 Replica Table。我在项目上吃过亏一开始图省事把业务库里的核心大表都复制了一份结果内存吃紧最后还得清理。现在我会按一套判断标准来筛选适合做复制表的通常是这几类报表和 BI 场景的底层数据表分析查询多而且 SQL 复杂跨库 JOIN 频繁每次查询都要多次经过网络往返性能不可控源库是传统业务库白天高负载不希望报表查询再去挤占它的资源表数据量在一定可控范围内且 HANA 侧有明确内存预算。不适合做复制表的我也列一下偶尔才查一次一次查几行的主数据表没必要落地需要秒级看到远端最新状态的实时查询场景复制表刷新再快也有延迟数据量极大比如几百亿行HANA 内存根本放不下源端表结构频繁变更复制任务维护成本远大于收益。我常用的做法是先在虚拟表上做一轮性能测试打开执行计划看算子是 Pushdown 还是本地处理。如果大部分过滤和聚合都被下推到远端执行而且单次查询还要等几秒甚至几十秒那这张表就值得评估落地副本。反过来如果查询本身很简单数据量又小虚拟表的延迟可以接受就完全没必要折腾复制表。3. 实操手把手把远端表变成 HANA 落地副本3.1 第一步创建 Remote Source先把通道打通不管用 SDA 还是 SDI第一步都是先创建 Remote Source。HANA 的语法大同小异以最常见的 HANA 到 HANA 远端源为例CREATE REMOTE SOURCE S4H_SOURCE ADAPTER hdb CONFIGURATION ServerNode10.10.10.20:30015 WITH CREDENTIAL TYPE PASSWORD USING userREPL_USER;password******;如果远端是 Oracle、SQL Server、Kafka 这类系统需要换对应的 Adapter 和配置参数。比如连 Oracle 要用ora适配器连 SQL Server 要用sapodbc或sqlserver具体可以在 HANA 的ADAPTERS系统视图中查到。创建完成后先别急着建表确认连接状态正常。可以查一下系统视图SELECT * FROM M_REMOTE_SOURCES; SELECT * FROM M_REMOTE_SOURCE_STATUS;确认源连接处于正常状态后再继续下一步。这个步骤很多人会跳过结果后面建虚拟表时报一堆连接错误来回折腾。另外权限方面要注意创建 Remote Source 需要CREATE REMOTE SOURCE权限使用远端连接还需要对应的 Schema 访问权限。如果建完以后查询提示无权限优先检查源端数据库给 REPL_USER 授权是否到位。3.2 第二步建虚拟表验证远端数据能查出来通道打通后创建虚拟表。假设远端源里有一张CONFIG.ORDERS我习惯在 HANA 这边的集成 Schema 下建一个对应的虚拟表CREATE VIRTUAL TABLE INT.VT_ORDERS AT S4H_SOURCE.CONFIG.ORDERS;建完后跑几个查询做验证。先看数量SELECT COUNT(*) FROM INT.VT_ORDERS;再看几条数据长什么样SELECT * FROM INT.VT_ORDERS LIMIT 100;这里要特别强调验证查询能跑通不代表性能好。我建议顺手用 EXPLAIN PLAN 看一下执行计划EXPLAIN PLAN FOR SELECT REGION, SUM(AMOUNT) FROM INT.VT_ORDERS GROUP BY REGION;如果执行计划里出现了 Remote、Pushdown 相关算子说明查询确实是下推到远端执行的。这块内容先记录下来后面做性能对比时要用。3.3 第三步用 CREATE TABLE AS SELECT 初始化副本虚拟表验证没问题就可以初始化本地副本了。我平时最常用的方式就是这条 SQLCREATE TABLE INT.ORDERS_COPY AS (SELECT * FROM INT.VT_ORDERS);这条语句会创建一张本地表并把虚拟表当前的数据批量写入。如果实例默认的表类型是列存这张副本表就是列存表直接享受 HANA 的压缩和列式扫描优势。如果想更稳妥地控制表类型可以拆成两步用CREATE COLUMN TABLE手动建表结构再用INSERT INTO ... SELECT ...灌数据。初始化完成后验证一下表的数据量和字段是否和源端对齐SELECT COUNT(*) FROM INT.ORDERS_COPY; SELECT COLUMN_NAME, DATA_TYPE_NAME FROM TABLE_COLUMNS WHERE SCHEMA_NAME INT AND TABLE_NAME ORDERS_COPY;这一步我建议做一下数据比对别只看行数。选几个关键字段做 SUM 或者 HASH 比对确保复制过程中没有类型截断或者精度丢损。3.4 第四步刷新策略增量还是全量初始化只是开始刷新策略决定副本能不能长期可用。对小的维度表我直接走全量刷新TRUNCATE TABLE INT.ORDERS_COPY; INSERT INTO INT.ORDERS_COPY SELECT * FROM INT.VT_ORDERS; COMMIT;这里要注意TRUNCATE 之后如果刷新失败表就是空的业务查询会直接受影响。稳妥的做法是先 INSERT 到一张临时表校验通过后再切换或者至少把刷新任务放在业务低峰期并做好失败告警。对带时间戳的大表我做增量刷新最经典的是这种写法INSERT INTO INT.ORDERS_COPY SELECT * FROM INT.VT_ORDERS WHERE CREATE_AT ( SELECT COALESCE(MAX(CREATE_AT), TO_TIMESTAMP(1970-01-01 00:00:00, YYYY-MM-DD HH24:MI:SS)) FROM INT.ORDERS_COPY ); COMMIT;如果源表存在 update 操作而不是纯追加那 INSERT 会漏掉修改过的老数据。这种情况我改用 UPSERT 或 MERGE 处理HANA 里 UPSERT 的写法相对简洁UPSERT INT.ORDERS_COPY SELECT * FROM INT.VT_ORDERS WHERE MODIFIED_AT ( SELECT COALESCE(MAX(MODIFIED_AT), TO_TIMESTAMP(1970-01-01 00:00:00, YYYY-MM-DD HH24:MI:SS)) FROM INT.ORDERS_COPY );不过 UPSERT 要求目标表必须有明确的主键否则 HANA 没办法判断该插入还是更新。建表的时候如果忘了定义主键这里会吃不少苦头。至于调度方式可以交给 HANA 自身的调度器、外部 cron 定期调 hdbsql、或 SAP BW 流程链触发。我的建议是刷新任务必须带日志至少记录开始时间、结束时间、影响行数。否则哪天数据对不上你只能干瞪眼。3.5 第五步验证本地副本查询性能和容量副本建好、刷新跑通最后做两件事性能验证和容量监控。性能验证很简单拿同一套复杂 SQL分别跑虚拟表和副本表对比执行时间。我在项目里见过一个典型的例子一个带三张表 JOIN 的报表查询虚拟表要跑 25 秒副本表落地后 1.2 秒就出结果差距快 20 倍。原因很简单本地列存表不需要网络往返也不依赖源库当时的负载。容量监控方面HANA 是内存数据库我得时刻关心副本表占了多少内存。可以这样查SELECT SCHEMA_NAME, TABLE_NAME, ESTIMATED_MEMORY_SIZE_IN_TOTAL / 1024 / 1024 AS SIZE_MB FROM M_CS_TABLES WHERE SCHEMA_NAME INT AND TABLE_NAME ORDERS_COPY;如果发现副本表越来越多内存快撑不住了第一件事就是清理不再需要的副本而不是盲目加内存。我见过太多项目HANA 内存告警排查下来全是冗余副本表。4. 常见问题与避坑经验4.1 类型映射不对复制出来的数据缺字段、报精度错误HANA 建虚拟表时会尝试把远端字段类型自动映射到本地类型。但这个自动映射不是万能的尤其是遇到 Oracle 的 NUMBER、SQL Server 的 DATETIME2、或者一些自定义类型时很容易出现映射异常。比如源表里有个字段是VARCHAR2(4000)HANA 侧映射成NVARCHAR(5000)一般没啥问题。但如果源表是RAW、BLOB映射到 HANA 后查询可能直接报错。更隐蔽的是精度问题DECIMAL(20, 8)源数据复制到 HANA 变成DECIMAL(18, 4)小数位直接被截断报表数字对不上业务方找上门才发现。我的规避办法是在虚拟表和副本表之间加一层 SQL 视图做显式类型转换。比如CREATE VIEW INT.V_ORDERS_CAST AS SELECT ORDER_ID, CAST(AMOUNT AS DECIMAL(20, 8)) AS AMOUNT, TO_TIMESTAMP(CREATE_AT) AS CREATE_AT FROM INT.VT_ORDERS;然后基于视图去初始化副本表。这样类型、精度都在自己的掌控里不会出莫名其妙的截断问题。4.2 源表没有时间戳增量同步怎么破这是项目里最头疼的问题。源表设计得比较老压根没有CREATE_AT、MODIFIED_AT这类字段你又想只同步变化的数据怎么办我试过的可行方案有三种。第一种是直接放弃增量全量刷新前提是表数据量不大。第二种是跟源库开发团队沟通在表上加维护字段由应用层在写入时维护MODIFIED_AT实践中还算靠谱。第三种就是上 SDI 的基于日志的 CDC让 HANA 直接读取源库的 redo log 或者归档日志来捕获数据变更不依赖业务字段。我个人不太推荐“靠主键自增 ID 做增量”的做法。主键最大 ID 只能捕获新增完全覆盖不了 update 和 delete 场景。你以为同步很正常结果数据永远是旧的那一版报表不准还很难发现。4.3 复制任务失败先查这三个地方复制表刷新任务挂掉先别慌按顺序排查。第一个查 Remote Source 本身。远端数据库是不是重启了账号密码是不是过期了网络有没有抖动。我遇到过好几次源库做了一次密码轮换复制任务直接失败日志里还报Connection refused一看密码早过期了。第二个查目标表状态。副本表是不是被其他事务锁住了或者被 DBA 意外 DROP 了又或者分区结构被修改过。刷新脚本里如果有 TRUNCATE表结构一变很容易报错。第三个查数据本身。增量同步时源端突然出现一条违反主键约束的数据或者某个字段长度爆掉都可能让整个批量 INSERT 中断。这种情况我建议把刷新脚本拆小批次或者把异常数据先抓出来而不是让一整批任务全部滚回去。4.4 副本表悄悄吃掉内存容量规划要趁早HANA 的容量规划里副本表占比经常被低估。很多人想的是源表库里 500GB压缩后放 HANA 50GB 总行了吧。实际上压缩比取决于数据特征宽表、随机字符串多的表压缩比可能只有 2:1而不像数字型列存那样能压到 10:1。我的经验是每张副本表在落地前先做一个采样压缩比测试在 HANA 里建临时表灌 100 万行看M_CS_TABLES里的估算内存再换算整体容量。千万别等上线了再补救。另外副本表建议按业务模块统一命名比如REP_ORDERS、REP_CUSTOMER集中放在一个 Schema后续做容量清理时一眼就能分辨哪张表是副本、哪张表是业务表。我见过生产环境里副本表和业务表混在一起DBA 想清理都不太敢下手。我的个人体会复制表听起来只是“建个表灌数据”这么简单实际操作里考验人的是刷新策略和容灾意识。虚拟表是外联副本表是内储两者互补不是一个淘汰一个。我现在的习惯是任何远端表接入 HANA先建虚拟表做评估确认查询模式和性能瓶颈再决定要不要转成落地副本。真心建议你也保持这个节奏不会过度设计也不会漏掉真正需要落地的表。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表