☰
SAP HANA负载管理实战:从工作负载分类到并发与内存限制的完整指南
2026/10/16 10:06:09 网站建设 项目流程

做SAP HANA运维这些年,最怕听到的一句话就是"报表系统跑不动了"。多半不是硬件缩水,而是SAP HANA负载管理没理清。内存数据库的调度方式跟传统数据库完全不一样,一个高并发查询就能把CPU吃满,几个大报表能把内存挤爆。这篇把HANA负载管理这套东西从原理到落地完整捋一遍,工作负载分类怎么配、优先级怎么定、内存和并发怎么限、排障路径怎么走,适合刚接手HANA的DBA,也适合做了几年但没系统看过负载管理的同行。每个人遇到的问题可能不同,但底层逻辑是通的。

1. 为什么说HANA负载管理,本质是内存与CPU的调度艺术

1.1 传统数据库的经验,在HANA这里会失灵

很多从传统数据库转过来的同事,第一反应是加索引、调SQL、扩内存。这些东西在HANA上有没有用?有用,但不是最关键的。

传统数据库的瓶颈大头在磁盘IO,慢了之后查询会被卡在IO等待上,反而变相"保护"了CPU和内存。HANA不一样,数据全在内存里,没有磁盘IO这道闸门。数据加载快、计算快,但也意味着一个没写好限制的查询,可以在极短时间内把CPU全部线程吃干抹净。没有了IO瓶颈的"自然限流",你必须主动给系统加闸门。

HANA大量使用列式存储和并行执行引擎。一个查询会被拆成多个算子并行跑,每个算子又可能开多个线程。如果同时进来几十个复杂报表查询,线程池瞬间被打满,内存被中间结果集堆满,后面所有查询包括健康的OLTP小事务,全都挤在一起等资源。表现出来的就是:整个系统变慢、CPU 100%、内存告警。

传统的锁等待还能靠锁监控定位,HANA这种资源等待,锁监视图里经常看不见东西,因为根本没有锁冲突,是纯粹的CPU和内存资源争抢。这是两个物种。

1.2 HANA负载管理到底管哪三件事

从实际运维视角看,HANA负载管理主要管三件事。

第一件事是分类。你不能让交易查询和大报表跑在同一条道上。通过工作负载分类,把不同用户、不同语句类型分到不同的"业务队列"里,每个队列有自己的特性参数。

第二件事是定优先级。同样是排队,不能让临时分析把核心生产查询堵住。通过优先级参数,让高优业务在资源争抢时占先,低优批处理靠边等。

第三件事是设上限。防止单个查询吃太多内存,防止某一类任务并发太高。通过语句内存限制和并发限制,把系统总资源的天花板守住。

这三件事做完了,负载管理的骨架就算搭起来了。后面所有细节,都是围着这三件事补血肉。

1.3 什么情况下你才真的需要负载管理

不是说所有HANA系统一上来就必须上负载管理。小系统、业务单一、查询量不大,默认配置完全够用。但出现下面几种苗头时,一定要开始动负载管理了。

第一类是典型的"混合负载"场景。OLTP和OLAP跑在同一套HANA上,ERP交易并发和报表分析并发叠加,互相拖累。第二类是"大查询失控"场景。某个特定报表逻辑复杂,跑起来就是几十亿行扫描,资源占用肉眼可见。第三类是"高峰期卡顿"场景。每到月末结账、每天早晨批量跑数的时候,系统响应时间明显劣化。

这三类情况,扩硬件只能缓解一时,因为问题根源是资源分配策略,不是资源总量。算一笔账:加内存、加CPU,成本高,而且大查询照样可以把新资源吃掉。给查询分好类、排好队、限好量,才是低成本的解决路径。

2. 工作负载分类:把好钢用在刀刃上的起点

2.1 workload class:一套参数定义一类业务

HANA里的核心概念叫workload class,中文叫工作负载类。可以把它理解成一张"业务标签卡",上面写清楚这类业务能用到多少资源、排多高的优先级、最多并行跑几个。

创建语法很直接:

CREATE WORKLOAD CLASS "OLTP_REALTIME" DESCRIPTION 'OLTP实时交易业务' PRIORITY_LEVEL 2 MAX_CONCURRENCY 20 STATEMENT_MEMORY_LIMIT 2 GB;
CREATE WORKLOAD CLASS "BATCH_REPORT" DESCRIPTION '批处理报表业务' PRIORITY_LEVEL 8 MAX_CONCURRENCY 5 STATEMENT_MEMORY_LIMIT 20 GB;

上面两个类,一个给OLTP实时交易,一个给批处理报表。PRIORITY_LEVEL 数值含义下面细说,先记住:OLTP类并发高、内存限制小、优先级高;批处理类并发低、内存限制大、优先级低。

名字上建议直接用业务含义命名,别用什么"CLASS_A""CLASS_B"。系统里workload class多起来之后,名字不说清楚根本没法维护。我曾经见过一个系统里有几百个workload class,名字全是"test1""test2"这种,后期排查到想骂人。

2.2 用户映射与会话级映射:两种绑定方式

建好workload class之后,怎么把业务放进去?最基础的方式是按用户绑定。

ALTER USER "SAP_ERP_APP" SET WORKLOAD CLASS "OLTP_REALTIME"; ALTER USER "REPORT_USER" SET WORKLOAD CLASS "BATCH_REPORT";

用户一改,他所有会话都会被拉到对应的workload class下。简单粗暴,适合用户和业务绑得比较死的场景。

但真实场景里,一个用户可能既要跑事务又要跑报表。按用户绑就绑不准了。这时候用会话级映射,单独指定某条连接走哪条道:

ALTER SYSTEM ALTER SESSION SET WORKLOAD CLASS "BATCH_REPORT";

这个命令在连接里执行后,仅当前会话变了。适合程序里有单独的分析连接池的情况。更灵活、更可控。

还有一个点容易忽略:改了workload class映射后,不是所有已存在的会话都立刻生效。会话建立时就已经绑定了当时的class,改完之后新建立的会话才会走新规则。运维操作时要注意这个生效时机,别改完以为生效了,结果发现旧会话还在老队列里跑。

2.3 触发器:让系统自己判断该走哪条道

用户映射和会话映射都是人工指定,但很多场景下,你希望系统自己识别。比如同一个报表用户,跑小查询时走OLTP道,跑大关联时自动改走批处理道。人工判断不现实,得靠触发器。

CREATE WORKLOAD TRIGGER "TR_BATCH_DETECT" WHEN STATEMENT TYPE(SELECT) ANALYZE STATEMENT STRING LIKE '%FROM%MATERIAL%' THEN SET WORKLOAD CLASS "BATCH_REPORT";

规则是:当语句是SELECT,并且SQL文本里包含某张关键大表的引用时,自动把这个语句分配到BATCH_REPORT类。

触发器最怕的是正则写太宽。LIKE '%FROM%'这种写法会把几乎所有SELECT都命中。建议触发器匹配条件一定要具体,用大表名、特殊提示词、固定语句特征。我见过一个系统,触发器写了一堆'%SELECT%',结果所有查询都被拉进批处理队列,OLTP业务被自己写的触发器给堵死了。触发器发布前,先统计一下当前活跃语句里有多少会命中规则,用实际SQL验证匹配范围,确认无爆炸性误命中后再上线。

2.4 优先级值别记反了:数值越小越优先

这是最容易踩坑的地方之一。PRIORITY_LEVEL取值范围是0到9,默认5。重点:0是最高优先级,9是最低优先级,跟常规认知里"数值越高越好"完全相反。

优先级影响的不只是CPU调度。在HANA里,优先级还会影响内存分配、锁请求仲裁等资源竞争行为。高优先级的语句在争抢资源和等待队列排位上,都明显比低优先级语句占优。

实际经验是:核心OLTP事务设1到2;面向管理层的固定报表设6到7;大批量批处理、数仓搬运类设8到9;临时分析类设7左右。把四种典型业务拉开差距后,高峰期的体验会明显改善。但差距也不是越大越好,过于极端会导致低优任务几乎得不到资源,反而不利于整体吞吐。

3. 并发与内存限制:拦住贪吃又捣乱的查询

3.1 MAX_CONCURRENCY:后厨只有一个灶台的时候怎么办

MAX_CONCURRENCY 限制的是同一个workload class里同时处于"正在执行"状态的语句数量。超过这个数的语句会进入排队状态,等前面的语句跑完再进去。

打个比方,一个餐厅后厨只有五个灶台。如果一次来了二十个订单,后厨只能同时炒五个菜,剩下十五个订单在窗口排队。HANA里这个参数就是在给后厨定灶台数量。

设置多少合适?不能拍脑袋。先看目前系统里这类业务高峰期并发是多少,然后砍掉百分之二三十,留下缓冲空间。比如批处理高峰期最多同时跑8个报表,MAX_CONCURRENCY先设5或6。太小了会人为制造排队,业务体验差;太大了没什么意义,保护作用不明显。

观察队列不一定要额外工具。系统视图里可以看到语句状态,如果大量语句显示排队中、等待资源,就说明并发上限设小了。调整是一个动态过程,改完观察一周再说。

3.2 STATEMENT_MEMORY_LIMIT:查询的内存贴标签

HANA里一个查询吃多少内存,直接影响整个系统的稳定性。列式存储下中间结果集可能极其庞大,一个大排序、大哈希连接能把可用内存瞬间吃光。

STATEMENT_MEMORY_LIMIT 给单个语句设了内存使用上限。超过这个上限时,语句会被终止并报错,不会让整个实例内存耗尽。

设置这块的思路跟并发不一样。并发是限制数量,内存限制是保护底线。建议按"正常业务最坏情况的1.5倍到2倍"来设。比如正常报表高峰期最占内存的查询用到6GB,那限制设10GB或者12GB,既留了余量,又不至于让单个查询失控。

千万别把语句内存限制设得太小。曾经有个同事把默认语句内存限制改成了512MB,结果所有正常的统计报表全都报内存超限,业务直接瘫痪。限制是为了拦住异常,不是为了为难正常业务。可以在压测环境先跑一遍典型查询流程,统计一下内存消耗分布,再定阈值。

3.3 队列观察:查询到底是在跑还是排队

很多运维同学看系统卡了,第一反应是看CPU使用率、内存占用率。这些指标在高负载下一定会报警,但报警了之后你还是不知道问题出在哪。

HANA的系统视图可以看到每个工作负载类下的实时状态,语句当前是正在执行还是排队。通过会话与负载类的关联视图,可以查某个用户、某类语句被分配到了哪个workload class,当前该类有多少并发语句。

写个小查询就能看清全局:

SELECT WORKLOAD_CLASS_NAME, COUNT(*) AS ACTIVE_CNT FROM M_ACTIVE_STATEMENTS GROUP BY WORKLOAD_CLASS_NAME;

更细一轮:

SELECT SESSION_ID, USER_NAME, STATEMENT_ID, WORKLOAD_CLASS_NAME, STATUS FROM M_WORKLOAD_SESSIONS WHERE WORKLOAD_CLASS_NAME LIKE 'BATCH%' ORDER BY STATUS;

如果BATCH类里大量语句状态是排队,说明并发上限吃紧;如果是正在执行,说明这些语句本身跑得慢。两层结论对应完全不同的处置方向,一个调参数,一个调SQL。

4. 从一次排障看HANA负载问题的完整定位链路

4.1 现象与第一反应

之前某制造企业的MES系统,每到下午三点左右,前端拣货终端就卡得不行。业务方反馈:扫描枪扫一个条码要转五秒,之前都是毫秒级。系统告警:HANA CPU 100%,内存使用率冲到90%以上。

我的第一反应不是看资源,而是先看有哪些语句在跑。

执行:

SELECT SESSION_ID, USER_NAME, STATEMENT_ID, CPU_TIME, MEMORY, STATUS, STATEMENT_STRING FROM M_ACTIVE_STATEMENTS ORDER BY MEMORY DESC;

结果很清晰:某张十几亿行的物料库存表上,跑着一个后台物料需求计划计算任务,单条语句内存占用占了整个实例的将近四分之一,CPU时间已经累积到几十分钟。后面大量拣货终端的小INSERT和短查询,全都堵在资源池外面排队。

4.2 从系统视图入手,先分清忙和乱

高负载时要分清楚:是"系统资源真的不够",还是"资源分配秩序出了问题"。

看事件等待视图。大量语句都在等待CPU或者内存资源,而不是等待锁。锁等待是不会把CPU打满的,但资源等待会。再结合活动语句列表,发现几乎所有大内存语句都来自同一个后台计划任务,基本可以定性:不是硬件不够,是一个"贪吃任务"把路占了。

再把会话跟负载类的关联视图捞出来,确认这个计划任务的会话属于哪个workload class。发现它绑定的是默认类,也就是跟OLTP交易同用一套默认参数,没有任何并发限制和内存限制。这就是问题根源。

4.3 定位到罪魁祸首后的处置

确认了元凶,处置分两步。

第一步是止血。把该条大查询会话终止掉,让系统资源先释放出来。用ALTER SYSTEM CANCEL SESSION,或者更重的KILL。先保证业务恢复。

第二步是治本。给这个计划任务专用一个workload class,限制并发为1,不允许它同时多开;设置语句内存上限,让它不能无限吃内存;优先级降到8或9,确保它在跟OLTP抢资源时永远靠边站。

核心逻辑是:后台批处理任务必须低人一等。它不是实时业务,晚跑十分钟没人投诉,但挤占了交易资源,整个产线都要投诉。

4.4 事后的配置补救

这个案例里最值得说的不是处置过程,而是后续配置。

计划任务的执行用户被单独划分出来,绑定到新创建的批处理类。同时补了一个触发器,当语句涉及核心大表且执行时间可能较长时,自动归入低优先级批处理道。即便将来换了用户、换了任务名,只要触发了匹配规则,还是会被拦下来。

又跑了两个月,同样的时段不再卡顿。CPU还是会冲到百分之七八十,因为低优先级任务也在跑,但OLTP交易的响应时间已经稳定在几百毫秒以内。资源还是那些资源,只是秩序变了。

排障的完整链路就是:现象确认、语句定位、原因定性、止血处置、配置根治、长期验证。每一步走扎实,不要跳步。

5. 一套能落地的HANA负载管理方案怎么搭

5.1 第一步:把业务负载分门别类

动手配置前先梳理业务,这步省不了。把系统里所有访问HANA的应用过一遍,列清楚每个应用是OLTP型、报表型还是批处理型,高峰时段大概什么时候,单条语句内存消耗水平怎么样。

梳理时最好让业务方参与确认,别自己拍脑袋。比如某个模块看起来像报表,实际上是对接产线的实时查询,搞错了会出大事。

整理出一个清单,包含:应用名称、典型用户、语句类型(SELECT/INSERT/UPDATE/DELETE)、平均内存、峰值内存、高峰并发、容忍延迟。这个清单就是后面所有参数设置的输入。

5.2 第二步:定优先级矩阵和并发阈值

清单出来了,就开始定策略。给每类业务定优先级和并发阈值,建议写成一张矩阵表,先跟团队评审再落配置。

业务类型典型用户优先级并发上限语句内存上限
核心OLTP生产执行、订单录入2202 GB
运营视图计划员、库管员5104 GB
固定报表领导层、财务月结668 GB
临时分析数据专员自建查询786 GB
后台批处理物料计划、库存重算8316 GB

矩阵里的数值不是标准答案,不同行业、不同机型差异很大。我这个是给中小型生产系统的典型起步值,拿回去要根据实际情况调整,重点是拉开层次,而不是追求某个具体数字。

5.3 第三步:落配置的完整SQL示例

矩阵评审通过后,开始写配置。先把workload class建出来:

CREATE WORKLOAD CLASS "WC_CORE_OLTP" DESCRIPTION '核心OLTP交易类' PRIORITY_LEVEL 2 MAX_CONCURRENCY 20 STATEMENT_MEMORY_LIMIT 2 GB; CREATE WORKLOAD CLASS "WC_VIEW_OPS" DESCRIPTION '运营查询类' PRIORITY_LEVEL 5 MAX_CONCURRENCY 10 STATEMENT_MEMORY_LIMIT 4 GB; CREATE WORKLOAD CLASS "WC_FIXED_REPORT" DESCRIPTION '固定报表类' PRIORITY_LEVEL 6 MAX_CONCURRENCY 6 STATEMENT_MEMORY_LIMIT 8 GB; CREATE WORKLOAD CLASS "WC_ADHOC" DESCRIPTION '临时分析类' PRIORITY_LEVEL 7 MAX_CONCURRENCY 8 STATEMENT_MEMORY_LIMIT 6 GB; CREATE WORKLOAD CLASS "WC_BATCH" DESCRIPTION '后台批处理类' PRIORITY_LEVEL 8 MAX_CONCURRENCY 3 STATEMENT_MEMORY_LIMIT 16 GB;

然后是映射。能按应用用户绑定的就直接绑定:

ALTER USER "MES_APP" SET WORKLOAD CLASS "WC_CORE_OLTP"; ALTER USER "PLANNER" SET WORKLOAD CLASS "WC_VIEW_OPS"; ALTER USER "REPORT_USER" SET WORKLOAD CLASS "WC_FIXED_REPORT";

临时分析类适合用会话级绑定,由应用侧在工具里指定。触发器兜底识别批处理:

CREATE WORKLOAD TRIGGER "TR_AUTO_BATCH" WHEN STATEMENT TYPE(SELECT, UPDATE) ANALYZE STATEMENT STRING LIKE '%MRP_RUN%' THEN SET WORKLOAD CLASS "WC_BATCH";

触发器里的匹配条件,必须先在生产环境的SQL审计或计划缓存里捞真实语句,验证命中率。不要想当然写一个字符串就上线。

5.4 第四步:上线验证与回滚策略

配置文件准备好后,选一个业务低谷窗口执行。执行完别马上走人,至少盯一个完整的高峰周期。

验证重点看几个维度:各类业务的响应时间是否有劣化;活跃语句里有没有大量排队;内存占用是否比配置前更平缓;有没有正常语句被内存限制误杀。

回滚策略必须提前想好。workload class本身删掉就行,映射关系ALTER回默认即可。关键是回滚后原问题可能立刻重现,所以变更窗口内要有人值守,该终止异常查询就终止,别等业务投诉。

6. 复盘之后,这几个坑值得单独拿出来说

6.1 优先级数值用反,等于没调

PRIORITY_LEVEL从0到9,0最高,9最低。这个跟Linux的nice值直觉相反,但比nice更反直觉的是,很多教程和资料里都没有专门强调这一点。

我见过不止一次,同事把核心业务设成9、批处理设成1,结果调完之后核心业务反而更卡了。排查半天,优先级方向搞反了。配置之前,写一行注释在脚本里:"数值越小优先级越高",能避免团队其他人重复踩坑。

6.2 MAX_CONCURRENCY设太小,报表排队排到怀疑人生

并发保护的本质是"限制同时跑的语句数量",不是"限制语句执行时间"。如果并发设得太小,执行时间又快不起来,排队长度会滚雪球。

判断办法:观察语句排队数量。如果排队的语句数量持续高于并发上限的两三倍,说明上限太紧了。适当调大,给正常峰值留足空间。记住,并发限制是用来防异常叠加的,不是用来限制正常业务的。

6.3 STATEMENT_MEMORY_LIMIT一刀切,正常查询也被误杀

内存限制最忌讳一刀切。一个系统里,简单主键查询可能只要几十MB,复杂聚合报表可能要几十GB。用同一个上限管所有人,必然有人被误伤。

正确做法是按workload class分别设,每类业务看典型的最高内存消耗,按1.5到2倍留余。宁可高一点,也别低到误杀正常语句。被误杀一次,业务方的信任要很久才能补回来。

6.4 触发器匹配规则太宽,全系统都乱了

触发器是自动化的利器,也是自动化的失控源。匹配字符串写得太宽,一个小小的LIKE可能把所有SQL都兜进去,业务瞬间全乱。

上线触发器之前,先在历史语句里做匹配演练,确认命中清单跟预期一致。触发器不是越全越好,匹配条件越具体越安全。宁可漏掉一小部分,让它走默认保守配置,也不要误伤核心业务。

6.5 别忘了内部任务和DDL不归workload class管

这是很多人忽略的一点。备份、恢复、DDL、一些系统内部任务,有自己的调度机制,不完全受workload class控制。你给某个用户配了低优先级类,但他执行DDL建索引时,行为可能跟普通DQL语句完全不同。

所以在评估负载管理效果时,不要把内部任务和DDL的波动也算进去。改善效果要看业务侧的实际响应时间,不是看系统CPU降了多少。内部任务该跑的还在跑,那块资源本来也不该指望靠workload class管住。

做负载管理这几年,我最大的体会是:SAP HANA不是靠单条优化解决性能问题,而是靠一套秩序。工作负载分类、优先级、并发和内存限制,这些机制单独看都不复杂,但组合起来,能把混合负载场景下的混乱变成可控。刚开始调整时,建议只动一两类业务,观察一段时间,确认正向收益后再逐步铺开。改动幅度越小,出问题时的定位范围越窄。最后再分享一个小经验:每次调整前把当前配置全量导出一份留着,出问题还能对比参数差异。这个习惯帮我省过不止一次回滚的大麻烦。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询