KingbaseES 列存储踩坑记:cstore_fdw 建表灌数全过程,以及数据改不动怎么办

又要从一个案例说起。

上个月我们组接了个电力监测平台的国产化改造,库是 KingbaseES V9R1C10,我负责其中分析查询那块的性能。原本以为是个常规活,结果在存储选型上卡了快两周,返工两次。这篇文章来把这两周踩的坑原样记下来,包括我一开始搞错的地方。

起因是一张事实表。设备采集明细,三十多个字段,每天新增三四千万行。业务侧的诉求其实很朴素:看某个区域某段时间的平均电压、最高温度、负载趋势。就这几个指标。但数据库每次执行都得把整行三十多列全读出来,然后在里面挑那三四个字段。表里有个 raw_payload 存原始报文,一个字段能占整行七成体积,从来没人查它,每行都得为它付 I/O。

我把这事跟同事吐槽,他说你这不就是典型的列存储场景吗。我说对,那就上列存吧。然后就开始踩坑了。

一、第一个坑:我以为加个参数就行

我最初的设想特别简单,网上搜了一圈,看到有文章写 WITH (orientation = column),也有写 storage_type='column' 的,还有写 USING COLUMNSTORE 的。三种说法互相打架,我挑了一个试,报错。换一个,还是报错。

后来老老实实去翻官方文档,才搞清楚:KingbaseES 现在的列存是 cstore_fdw 这个扩展插件提供的,版本 V1.7。它不是原生存储引擎,是个 FDW。

FDW 这个身份很关键,我一开始没当回事,后面所有坑基本都从这儿来。你建出来的列存表,在数据库眼里是一张 外部表(FOREIGN TABLE),不是普通表。所以它有一堆"不像表"的脾气:

  • 单条 INSERT 不支持
  • UPDATE、DELETE 都不支持
  • 建表时写的约束不报错,但也不生效
  • 执行计划里它显示 Foreign Scan,优化器对它的行数估算经常不准

第四条是我后来才意识到的,代价是一条报表 SQL 跑了两个多小时没出结果,这个后面细说。

顺带说下网上那三种写法的来源。我猜是不同版本、不同兼容模式下的东西混在一起了,也可能有些是别家库的语法被张冠李戴。总之以你自己环境为准,我这篇文章里的 SQL 都是 V9R1C10 + 麒麟 V10 + 鲲鹏 920 上跑过的,版本不一样的话参数名应该没问题,默认值最好自己再确认一遍。

二、装插件,三步,少一步都不行

这块很简单,但我还是写一下,因为漏掉任何一步,报错信息都挺有误导性的。

第一步,改 kingbase.conf:

bash 复制代码
vi $KINGBASE_DATA/kingbase.conf

找到 shared_preload_libraries,加上:

复制代码
shared_preload_libraries = 'cstore_fdw'

必须重启实例,reload 没用。

我第一次就栽在这儿。当时急着验证效果,改完只 reload 了一下,然后建表、灌数一路顺畅做到 COPY,才在执行的时候报了个 cannot copy to foreign table 的错。这个报错完全没提预加载的事,我查了挺久。所以建议改完之后先确认:

sql 复制代码
SHOW shared_preload_libraries;

能看到 cstore_fdw 再往下走。

第二步,建扩展和 SERVER:

sql 复制代码
-- 每个库做一次就够了
CREATE EXTENSION cstore_fdw;

-- 这个名字随便起,后面建表时对上就行
CREATE SERVER cstore_server FOREIGN DATA WRAPPER cstore_fdw;

-- 有些环境不 LOAD 一下会出问题,加上不亏
LOAD 'cstore_fdw';

第三步:没了,就这些。官方文档说这个插件不需要额外配参数,这点挺省事。

三、建表:行存和列存各建一张

我先说下我的表结构,后面所有 SQL 都基于它。设备采样明细,字段大概是:

  • dev_id 设备编号
  • sample_time 采样时间
  • region 所属区域
  • voltage / current / temperature 三个采集指标
  • status 状态码
  • raw_payload 原始报文,TEXT,长,没人查
  • remark 备注

行存表

这张表承接业务写入,正常增删改查都打在它身上:

sql 复制代码
CREATE TABLE t_device_sample_row (
    id            BIGSERIAL,
    dev_id        VARCHAR(32)  NOT NULL,
    sample_time   TIMESTAMP    NOT NULL,
    region        VARCHAR(32),
    voltage       NUMERIC(10,2),
    current       NUMERIC(10,2),
    temperature   NUMERIC(6,2),
    status        SMALLINT,
    raw_payload   TEXT,
    remark        VARCHAR(200),
    CONSTRAINT pk_device_sample_row PRIMARY KEY (id)
);

插一句新手容易踩的:KingbaseES 的整数类型不带长度 。从别家库过来习惯写 INT(10) 的,到这里直接语法错。就写 INT、BIGINT、SMALLINT,别加括号。我们组新来的实习生在这上面卡了大半天,跑来问我,我说我第一次也这么写过。

另外 NUMERIC(10,2) 这种建议显式写精度,别偷懒写 NUMERIC。不写的话它会按你输入的样子原样存,后面做聚合和比较的时候容易出些莫名其妙的问题。

列存外部表

sql 复制代码
CREATE FOREIGN TABLE t_device_sample_col (
    dev_id        VARCHAR(32),
    sample_time   TIMESTAMP,
    region        VARCHAR(32),
    voltage       NUMERIC(10,2),
    current       NUMERIC(10,2),
    temperature   NUMERIC(6,2),
    status        SMALLINT
)
SERVER cstore_server
OPTIONS (
    filename          '/data/kes/cstore/t_device_sample_col',
    compression       'zstd',
    stripe_row_count  '150000',
    block_row_count   '10000'
);

注意我没把 raw_payload 和 remark 放进列存表。这个决定后来证明是对的。列存的优势本来就建立在"只读写得着的列"上,你把没人查的大字段塞进去,等于自己把优势抵消掉。原始报文要留着归档,另建一张行存表更划算。

OPTIONS 这四个参数怎么填

参数 干什么的 默认 我的取舍
filename 数据文件绝对路径前缀 安装目录下的 cstore_fdw 生产上一定要显式指定,单独挂盘
compression 压缩算法,none/zstd/dict none 默认不压缩,这个必须手动改
stripe_row_count 每个 stripe 多少行 150000 内存紧就调小,性能会跟着掉
block_row_count 每个列块多少行 10000 调大压缩好,调小跳读准

默认 compression = none 这个事我得单独说。我当时建完表直接灌了几百万行试,一看磁盘占用几乎没变化,还以为列存没生效,白紧张一场。后来才发现是压根没开压缩。这个默认值我觉得有点坑,各位建表时记得显式指定。

zstd 还有个单独的压缩级别可以调:

sql 复制代码
-- 范围 0~9,默认 1
SET cstore_fdw.zstd_compression_level = 3;

我设到 3。理由是我们晚上批量灌数、白天纯查询,灌数那会儿 CPU 闲着也是闲着。你要是实时灌数,就别往上调了,压缩是要吃 CPU 的。

block_row_count 顺便解释下。列存除了只读需要的列,还靠一个叫跳跃索引的东西:每个数据块记下这块的最大最小值,过滤条件跟这个范围不相交,整块直接跳过,连解压都省。块划得大,压缩率高、读盘次数少,但跳的粒度粗;划得小,跳得准,但元数据多、压缩差。我一般先用默认,跑一轮 EXPLAIN 看看再说。

四、灌数据:两种方式,别用第三种

方式一:INSERT INTO ... SELECT

这是我在生产上唯一用的:

sql 复制代码
INSERT INTO t_device_sample_col
SELECT dev_id, sample_time, region, voltage, current, temperature, status
FROM t_device_sample_row
WHERE sample_time >= DATE '2024-01-01'
  AND sample_time <  DATE '2024-02-01';

按时间切批,一次灌一个月。出问题只影响一个批次,重建也快。

方式二:COPY

sql 复制代码
COPY t_device_sample_col
FROM '/data/import/sample_202401.csv'
WITH (FORMAT csv, HEADER true);

外部导出的 CSV 走这个最快。用 ksql 的话记得是 \COPY,不是 COPY------前者是客户端路径,后者是服务端路径,新手经常在这里混,报个文件找不到还以为是权限问题。

第三种方式:不行

sql 复制代码
-- 这条会报错
INSERT INTO t_device_sample_col
VALUES ('DEV001', NOW(), 'GUANGZHOU', 220.5, 15.3, 42.1, 1);

单条 INSERT 不支持。官方给的解释我觉得挺实在:每灌一批数据至少生成一个数据块,要是允许一条一条插,每插一条多一个块,块数爆炸,反而更慢。

道理我认,但它确实改变了开发习惯。业务侧的写入必须落在行存表上,列存表只接受批量导入。 这一点要在设计阶段就跟业务方讲清楚,别等联调的时候才发现对不上。

灌完一定 ANALYZE

sql 复制代码
ANALYZE t_device_sample_col;

官方说这步可选,我强烈建议每次灌完都跑。外部表的统计信息不会自动更新得那么勤快,统计一旧,优化器估算的行数就离谱,很容易给你挑个烂计划。

我们有个日报突然从 3 秒变成 40 多秒。查了两天,最后发现是那批数据灌完忘了 ANALYZE。两天时间,就这么没了。

五、查询:写几条真在跑的

最典型的聚合:

sql 复制代码
SELECT region,
       COUNT(*)                    AS sample_cnt,
       ROUND(AVG(voltage), 2)      AS avg_voltage,
       ROUND(AVG(current), 2)      AS avg_current,
       MAX(temperature)            AS max_temp
FROM t_device_sample_col
WHERE sample_time >= DATE '2024-01-01'
  AND sample_time <  DATE '2024-02-01'
GROUP BY region
ORDER BY sample_cnt DESC;

这个查询只碰五列。行存里要把每行三十多列全读出来再挑字段;列存里只读这几列的数据块,raw_payload 那类字段压根不在表里,连读的机会都没有。

按小时看趋势,时间归到整点:

sql 复制代码
SELECT date_trunc('hour', sample_time) AS hour_bucket,
       COUNT(*)                        AS cnt,
       ROUND(AVG(current), 2)          AS avg_current,
       MAX(temperature)                AS max_temp
FROM t_device_sample_col
WHERE sample_time >= DATE '2024-01-01'
  AND sample_time <  DATE '2024-01-02'
GROUP BY hour_bucket
ORDER BY hour_bucket;

带过滤的明细查询,region 是低基数字段,列存里压完体积很小:

sql 复制代码
SELECT dev_id, sample_time, voltage, temperature
FROM t_device_sample_col
WHERE region = 'GUANGZHOU'
  AND temperature > 80
  AND sample_time >= DATE '2024-01-01'
  AND sample_time <  DATE '2024-02-01'
ORDER BY temperature DESC
LIMIT 100;

环比日均值,上窗口函数:

sql 复制代码
SELECT region,
       TO_CHAR(date_trunc('day', sample_time), 'YYYY-MM-DD') AS stat_day,
       ROUND(AVG(voltage), 2) AS avg_voltage,
       LAG(ROUND(AVG(voltage), 2)) OVER (
           PARTITION BY region
           ORDER BY date_trunc('day', sample_time)
       ) AS prev_day_voltage
FROM t_device_sample_col
WHERE sample_time >= DATE '2024-01-01'
  AND sample_time <  DATE '2024-02-01'
GROUP BY region, date_trunc('day', sample_time)
ORDER BY region, stat_day;

关于 JOIN,我要多嘴

列存表跟行存维表关联是正常的,我们有一张设备维表存型号和所属场站:

sql 复制代码
SELECT d.station_name,
       COUNT(*)                 AS cnt,
       ROUND(AVG(c.current), 2) AS avg_current
FROM t_device_sample_col c
JOIN t_device_dim d ON c.dev_id = d.dev_id
WHERE c.sample_time >= DATE '2024-01-01'
  AND c.sample_time <  DATE '2024-02-01'
GROUP BY d.station_name
ORDER BY cnt DESC;

但我要提醒一句:列存表在计划里是 Foreign Scan,优化器对它的代价估算不如普通行存表准。凡是带 JOIN 的查询,一定先 EXPLAIN 确认驱动顺序。

前面说的那个跑了两个多小时的报表就是这么来的。五表关联,优化器把列存大表选成了驱动表。我盯着执行计划看了半天才反应过来,用小表驱动之后降到 8 秒。两个多小时对 8 秒,这个差距我自己都觉得离谱。

现在我们的规矩是:列存参与的关联查询,上线前必看计划。

行存和列存能不能一起查

能。有时候业务要查的跨度跨越了"已灌列存的历史"和"还在行存的当天数据",那就 UNION ALL 拼一下:

sql 复制代码
SELECT region, ROUND(AVG(voltage), 2) AS avg_voltage
FROM (
    SELECT region, voltage
    FROM t_device_sample_col
    WHERE sample_time >= DATE '2024-01-01'
      AND sample_time <  DATE '2024-02-01'
    UNION ALL
    SELECT region, voltage
    FROM t_device_sample_row
    WHERE sample_time >= DATE '2024-02-01'
      AND sample_time <  DATE '2024-02-02'
) t
GROUP BY region;

这个写法在我们这儿用得挺多,尤其是月度报表跑到月末那几天。要注意的是两边的字段类型得对上,不然 UNION 会报类型不匹配------NUMERIC(10,2) 和 NUMERIC 混用的时候就容易出这种事,写的时候盯着点。

怎么确认真的省了空间

改完之后总得验证一下效果。查表大小可以这样:

sql 复制代码
-- 行存表占多少
SELECT sys_size_pretty(sys_relation_size('t_device_sample_row'));

-- 列存表的情况得看文件目录
SELECT count(*) FROM t_device_sample_col;

列存表是外部表,sys_relation_size 这类函数查到的不是真实数据文件大小。所以更直接的办法是去看你 filename 指定的那个目录下文件实际占了多少:

bash 复制代码
du -sh /data/kes/cstore/

我们环境里,同一批数据放列存(开 zstd)比放行存小了一大截,具体倍数我就不报了------不同数据特征差得挺远,我这个数对你没什么参考价值。建议你拿自己的真实数据灌一遍再判断,别信任何文章里给的压缩比数字,包括我这篇。

空间之外我还顺手记了几个数:灌数耗时、ANALYZE 耗时、几条核心报表的执行时间。这些建议做成一张表留档,后面调参数的时候有个基线能对比,不然改完也不知道是变好还是变差了。

EXPLAIN 看什么

sql 复制代码
EXPLAIN (ANALYZE, BUFFERS)
SELECT region, COUNT(*)
FROM t_device_sample_col
WHERE sample_time >= DATE '2024-01-01'
GROUP BY region;

我一般看这三个:

  • rows= 前后两个数差得远不远。远了就是统计信息该更新了
  • Shared read blocks,真正读了多少块。列存省不省就看它
  • 有没有 Sort Method: external merge Disk。有的话排序落盘了,work_mem 给小了

work_mem 可以会话级临时调大:

sql 复制代码
SET work_mem = '128MB';

不建议在实例级直接给个很大的值。work_mem 是每个排序、哈希操作单独分配的,并发一上来内存就爆。我只给跑批和分析的会话在连接后设一次。

六、最大的坑:数据改不动、删不掉

现在说说真正让我纠结的部分。

sql 复制代码
-- 这两句都会失败
UPDATE t_device_sample_col SET status = 2 WHERE dev_id = 'DEV001';
DELETE FROM t_device_sample_col WHERE sample_time < DATE '2023-01-01';

不支持 UPDATE,不支持 DELETE。这不是 bug,是设计------列存的数据块是压缩后连续存放的,改其中一个值意味着整块解压、改、再压缩,代价高得离谱。

我看到这条的时候心里是有点崩溃的。当时的想法是,一个不能改数据的表,能干嘛?差点就把方案推翻了。

后来想通了:限制没那么致命,但你得提前按"数据不可变"的思路去设计。 等线上跑起来才发现改不动,那就真麻烦了。

方案一:双层表(我现在用的)

架构长这样:

复制代码
业务写入  →  行存表 t_device_sample_row(正常增删改查)
                    ↓  定时批量
              列存表 t_device_sample_col(只查)

业务的 INSERT、UPDATE、DELETE 照旧打在行存表上,行存表该建索引建索引。夜里跑一次增量:

sql 复制代码
-- 把该时间窗的数据重新灌一遍
INSERT INTO t_device_sample_col
SELECT dev_id, sample_time, region, voltage, current, temperature, status
FROM t_device_sample_row
WHERE sample_time >= DATE '2024-01-01'
  AND sample_time <  DATE '2024-02-01';

-- 别忘这一步
ANALYZE t_device_sample_col;

核心就一句话:列存表是行存表的一个只读快照,永远从源头重建,不在原地改。

"重新灌一遍"之前得先把窗内的旧数据清掉,清理走方案二。

方案二:建新表 + 原子换名

要删历史数据、修正一批错误数据,用重建:

sql 复制代码
-- 1. 建一张结构一样的新表,filename 换个名字
CREATE FOREIGN TABLE t_device_sample_col_new (
    dev_id        VARCHAR(32),
    sample_time   TIMESTAMP,
    region        VARCHAR(32),
    voltage       NUMERIC(10,2),
    current       NUMERIC(10,2),
    temperature   NUMERIC(6,2),
    status        SMALLINT
)
SERVER cstore_server
OPTIONS (
    filename          '/data/kes/cstore/t_device_sample_col_new',
    compression       'zstd',
    stripe_row_count  '150000',
    block_row_count   '10000'
);

-- 2. 只把要保留的灌进去,要删的在这儿被 WHERE 掉
INSERT INTO t_device_sample_col_new
SELECT dev_id, sample_time, region, voltage, current, temperature, status
FROM t_device_sample_col
WHERE sample_time >= DATE '2023-01-01';

-- 3. 统计信息
ANALYZE t_device_sample_col_new;

-- 4. 换名,两句放一个事务里
BEGIN;
ALTER TABLE t_device_sample_col     RENAME TO t_device_sample_col_old;
ALTER TABLE t_device_sample_col_new RENAME TO t_device_sample_col;
COMMIT;

-- 5. 确认没问题再删
DROP FOREIGN TABLE t_device_sample_col_old;

第 4 步放事务里是因为:两句 RENAME 之间有个中间态,这时候业务查过来会扑空。放一个事务里就没这个窗口了。

重建完还有一件事:旧表的数据文件不会自动删。

你用 filename 指定的那些文件还躺在磁盘上,DROP FOREIGN TABLE 之后记得手动清理。我就吃过这个亏------某天监控报警磁盘涨到 85%,排查半天发现是前三次重建留下的老文件。现在我们的重建脚本里强制带一个清理步骤。

七、跟分区搭着用

列存外部表本身我没试成功做分区,我的做法是行存分区 + 按分区灌列存。

行存表按月份范围分区:

sql 复制代码
CREATE TABLE t_device_sample_row (
    id            BIGSERIAL,
    dev_id        VARCHAR(32)  NOT NULL,
    sample_time   TIMESTAMP    NOT NULL,
    region        VARCHAR(32),
    voltage       NUMERIC(10,2),
    current       NUMERIC(10,2),
    temperature   NUMERIC(6,2),
    status        SMALLINT,
    raw_payload   TEXT
)
PARTITION BY RANGE (sample_time)
(
    PARTITION p202401 VALUES LESS THAN ('2024-02-01'),
    PARTITION p202402 VALUES LESS THAN ('2024-03-01'),
    PARTITION p202403 VALUES LESS THAN ('2024-04-01'),
    PARTITION pmax    VALUES LESS THAN (MAXVALUE)
);

分区在这儿的三个好处:

归档方便。 一个月份封板之后基本不会再变,正好对上列存"只追加不修改"的脾气。

重灌粒度可控。 哪个月数据有问题,只重建那一个月的列存表,不用动全量。

分区裁剪。 行存侧查询能自动跳过无关分区。

现在的节奏是每月 5 号之后(上月数据基本不会再改了),把上月分区灌成独立列存表,表名带年月后缀。历史月份的列存表就是死数据,查得快,也不用再管同步。

顺带说下 Oracle 兼容模式。如果你的库是 Oracle 模式,分区语法基本能照搬,VALUES LESS THAN (TO_DATE(...))、MAXVALUE 这些都支持,PARTITION (p202401) 这种指定分区查询也能用。这块我没深挖,有兴趣的可以自己测测。

八、剩下几个坑,列个单子

约束建了不生效。

sql 复制代码
CREATE FOREIGN TABLE t_test (
    id   INT PRIMARY KEY,      -- 不报错,也不生效
    name VARCHAR(50) NOT NULL   -- 同上
) SERVER cstore_server;

这条必须单独拎出来,因为它不报错。建表时写的主键、非空、CHECK,数据库全默默接受,然后默默忽略。数据校验必须前置到灌数之前,或者在行存源表上做。

我们有个批次源数据里混进了 NULL 的 region,灌进去之后 GROUP BY 多出一个空分组,报表对不上账。查了两天。

灌数顺序影响压缩率。

同列数据越相似压得越好。数据如果能按某个低基数列排序后灌入(比如先按 region 排),压缩效果明显好于乱序。不是必须的,但属于顺手就能拿的收益:

sql 复制代码
INSERT INTO t_device_sample_col
SELECT dev_id, sample_time, region, voltage, current, temperature, status
FROM t_device_sample_row
WHERE sample_time >= DATE '2024-01-01'
  AND sample_time <  DATE '2024-02-01'
ORDER BY region, sample_time;   -- 就加这一句

别指望在列存表上建索引。

它靠跳跃索引过滤,你再建 B 树意义不大。优化思路要换:与其想着建索引,不如想想怎么让过滤条件跟数据分布对齐。

并行这块我没搞太明白。

列存走 Foreign Scan,能不能并行、并行度多少,跟版本和实现都有关。我 EXPLAIN 看过几轮,没稳定出现并行。所以别把期望全压在并行上,max_parallel_workers_per_gather 按需调调就行,别一上来给个很大的值,上下文切换的开销可能比收益还大。这块如果有朋友研究透了,欢迎评论区指正。

磁盘要提前规划。

filename 指定的路径最好单独挂盘。列存表重建期间新旧两份数据同时在,空间按两倍预留。见过有人磁盘不够,重建到一半失败,两边都不可用。

九、什么情况别用列存储

讲了半天好处,也说下不适合的地方。这几种我建议老老实实用行存:

  • 高频单行查询。 按主键查一条,行存 + B 树是碾压性的,列存为聚合设计的那套机制一点用不上
  • 要频繁更新的业务表。 前面说了,改不动
  • 小表。 几万行的表你根本感觉不出差别,反而多一套同步链路要维护
  • 事务要求高的场景。 列存表是分析副本的定位,别当主库用

我自己的判断标准就两条:写进去之后是不是基本不改了,查询是不是总盯着少数几个字段做聚合。 两条都满足,上列存;只满足一条,或者都不满足,别折腾。

十、几个被问得多的问题

问:能不能整库都改成列存?

别。见过有团队图省事把所有表都建成列存,结果业务侧的单点查询全线变慢,还因为改不动数据被迫天天重建表。列存只适合做分析副本,主业务表该行存还是行存,这个边界别模糊。

问:灌数据时业务能不能同时查?

能查,但查到的是旧数据,新灌进去的部分在事务提交前对别人不可见。我们统一安排在业务低峰期灌,灌完立刻 ANALYZE。要是业务要求严格一致,就走"建新表 + 原子换名"。

问:一张列存表多大合适?

没标准答案,跟内存和查询模式都有关。我的经验是千万到几亿行这个量级,再大就按时间拆。拆的好处是重建快、出问题影响面小。我们按月拆,单表两亿行上下,重建一次十几分钟,能接受。

问:统计信息多久刷一次?

每次批量灌完就刷,别偷懒。手动 ANALYZE 最保险,别指望后台自动维护能把外部表管好。

问:日常要维护些什么?

我们现在的日常就三件事:每天夜里跑增量灌数、灌完 ANALYZE、每月初做一次历史月份的重灌。另外加了个磁盘监控,专门盯 filename 那个目录,因为重建残留文件这事栽过一次,现在必须看着。

再就是慢 SQL 的定期巡检。列存表参与的查询,如果某条突然变慢,我第一反应是去查两样:统计信息是不是过期了,执行计划的驱动顺序是不是变了。九成的问题都出在这两处。

最后

回头看这两周,技术上最难的不是 SQL 怎么写,是思维方式的转换。我们太习惯"一张表包打天下",习惯随时 UPDATE 一行数据。列存逼着你把数据分成"会变的"和"不会变的"两类,各用各的存储。

这个分层想明白之后,事情就顺了:行存承接增删改查,列存承接分析查询,中间一道定时批量同步。架构多一层,换来分析响应速度和存储成本的双重改善,我觉得值。

还有个意外收获。梳理完之后我们顺带把数据生命周期理清楚了------哪些数据会变,哪些三个月后没人看,哪些要永久保留。这个结论不光服务于存储选型,备份策略和归档策略也跟着清晰了,算一鱼两吃。

最后提醒一下:我这儿的参数默认值都来自官方手册,但版本差异这事儿在数据库上永远要留个心眼。上生产前建议在测试环境把建表、灌数、查询、重建这套流程完整跑一遍,重建换名那几步尤其要先练熟。

相关推荐
我科绝伦(Huanhuan Zhou)1 小时前
Oracle 体系结构深度解析:从内存、进程到日志与事务一致性的全链路技术详解
数据库·oracle
一木 之林1 小时前
LangChain 第8章 记忆系统:短期/长期记忆与 PostgreSQL 持久化
数据库·postgresql·langchain
qq_452396231 小时前
第七篇:《向量数据库选型:从 Chroma 到 Milvus 的落地对比》
数据库·milvus
云絮.1 小时前
mybatis(二)
java·数据库·mybatis
yyuuuzz1 小时前
云服务器搭建个人博客记录:一次访问超时的复盘
运维·服务器·数据库
花间相见1 小时前
【计算基础|MySQL06】MySQL 架构与一条 SQL 的旅程
数据库·后端
oradh1 小时前
Oracle 分析函数使用总结
数据库·oracle
updayday8542 小时前
印染产线电脑进程异常占用资源却要逐台排查 - Ping64 远程进程管理
大数据·网络·数据库·安全·智能路由器
QYRdata2 小时前
年复合增长率8.2%!2026-2032年数据库开发服务赛道增长动能持续释放
数据库·服务发现·数据库开发·恒州博智