惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 【当耐特】
N
Netflix TechBlog - Medium
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
雷峰网
雷峰网
MongoDB | Blog
MongoDB | Blog
有赞技术团队
有赞技术团队
Engineering at Meta
Engineering at Meta
M
MIT News - Artificial intelligence
Google DeepMind News
Google DeepMind News
罗磊的独立博客
Hugging Face - Blog
Hugging Face - Blog
WordPress大学
WordPress大学
T
Tailwind CSS Blog
小众软件
小众软件
J
Java Code Geeks
人人都是产品经理
人人都是产品经理
博客园_首页
MyScale Blog
MyScale Blog
博客园 - 聂微东
V
Visual Studio Blog
The Cloudflare Blog
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
U
Unit 42

博客园 - AlfredZhao

Docker 删除 none 镜像:一次真实的清理记录 sed 一条命令批量替换 SQL 文件路径 执行新项目 python 脚本前,先用 conda 建一个独立环境 Git 提交代码:从报错到 SSH 免密推送 GitHub 克隆他人私有仓库:从授权到下载 理解Oracle Property Graph:以账户转账示例完成图特性最小测试 APEX 无法分配 SH 用户?一个存储过程轻松解决 SH 中文化样例数据使用手册 Oracle 排除非业务表:一份能直接抄的“全量过滤”SQL 进程都杀了,为什么 `netstat` 还能看到端口? MAC 空间告急?Codex 的 156GB 缓存垃圾,这样清! 人工清理问题数据:先查准,再删除 TK(Trusted Knowledge)为何而生? 使用快捷键快速切换 Mac 外接显示器模式 客户环境 Nginx 配置:流式报表与超时排查要点 Security Central:数据库安全的统一控制与运营平台 Palantir 眼中的一次“订单可能延期”,如何成为实时决策的起点? 从一条订单消息到 Bronze、Silver、Gold:我的第一次 Kafka + Lakehouse 实验 UUID v4 与 v7:同样是唯一 ID,为什么数据库表现可能完全不同? 用 crontab 给 LLM 使用量装上“监控眼” DeepSeek 与 GPT API 价格调整:该关注什么? 查看 Oracle 数据库中的定时任务执行情况 Codex 专用用户登录后自动进入默认项目目录 Mac 小技巧:用方向键优雅处理超长网址 Oracle GDD 与 Raft:别把共识机制和数据主权混为一谈 在 Oracle APEX 中用 BGE_BASE 生成向量:从模型导入到历史数据更新 行业人+AI:真正有价值的四个关键要素 知识库文件解析失败:一次由 Domain Index 引发的定位记录 Unicode 码位数、UTF-8 字节数、中英文差异和 Oracle 长度别再混淆了 Skill 的使用:从路径到能力边界
Oracle Property Graph 结合 In-Memory 的性能验证
AlfredZhao · 2026-09-19 · via 博客园 - AlfredZhao

2026-09-19 06:36  AlfredZhao  阅读(0)  评论()    收藏  举报

在之前的文章理解Oracle Property Graph:以账户转账示例完成图特性最小测试中,笔者用账户转账场景验证了属性图的基本查询能力。这次继续往前走一步:当图查询的数据量变大时,开启 In-Memory 到底能带来多少收益?下面用一条真实的多跳图查询来对比。

01 | 准备测试数据

沿用之前的图查询,但原始数据只有 6 条,量太小根本用不上 IM。于是笔者快速补了 1 万条账户和 1 万条转账记录:

-- 1. 生成 10,000 个账户(ID: 7 ~ 10006)
INSERT INTO money_accounts (account_id, account_name)
SELECT 
    6 + LEVEL AS account_id,
    '账户_' || (6 + LEVEL) AS account_name
FROM DUAL
CONNECT BY LEVEL <= 10000;

-- 2. 生成 10,000 条转账记录(ID: 107 ~ 10106)
INSERT INTO money_transfers (transfer_id, from_account_id, to_account_id, amount, transfer_time)
SELECT 
    106 + LEVEL AS transfer_id,
    TRUNC(DBMS_RANDOM.VALUE(1, 10007)) AS from_account_id,
    TRUNC(DBMS_RANDOM.VALUE(1, 10007)) AS to_account_id,
    ROUND(DBMS_RANDOM.VALUE(10, 5000), 2) AS amount,
    SYSTIMESTAMP - NUMTODSINTERVAL(DBMS_RANDOM.VALUE(0, 30), 'DAY') AS transfer_time
FROM DUAL
CONNECT BY LEVEL <= 10000;

COMMIT;

02 | 加载到内存列存

要让 IM 生效,先把底层两张表标记为 INMEMORY,并强制 Populate:

ALTER TABLE money_accounts INMEMORY;
ALTER TABLE money_transfers INMEMORY;

BEGIN
  DBMS_INMEMORY.POPULATE('SH', 'MONEY_ACCOUNTS');
  DBMS_INMEMORY.POPULATE('SH', 'MONEY_TRANSFERS');
END;
/

select SEGMENT_NAME, INMEMORY_SIZE, BYTES_NOT_POPULATED from v$im_segments;

bytes_not_populated 必须为 0,才说明数据已全部进入内存列存。

03 | 开启 In-Memory 的测试

SET AUTOTRACE ON;
SET TIMING ON;

SELECT *
FROM GRAPH_TABLE(
  money_graph
  MATCH (a IS ACCOUNT)-[IS TRANSFER]->{1,5}(b IS ACCOUNT)
  COLUMNS (
    a.account_id   AS source_account,
    a.account_name AS source_name,
    b.account_id   AS target_account,
    b.account_name AS target_name
  )
)
WHERE source_account = 1
ORDER BY target_account;

执行计划中,两张表的扫描方式都是 TABLE ACCESS INMEMORY FULL。多次执行后稳定结果:Elapsed 约 00:00:00.110,逻辑读 614400 logical read bytes from cache

04 | 关闭 In-Memory 的测试

图查询比较复杂,用 NO_INMEMORY Hint 有时不彻底,所以直接去掉表的 INMEMORY 属性更直观:

ALTER SYSTEM FLUSH BUFFER_CACHE;

ALTER TABLE money_accounts NO INMEMORY;
ALTER TABLE money_transfers NO INMEMORY;

SET AUTOTRACE ON;
SET TIMING ON;

再次执行同一条查询,扫描方式变回 TABLE ACCESS FULL。稳定结果:Elapsed 约 00:00:00.125,逻辑读 6897664 logical read bytes from cache

05 | 该看哪些指标

对比两组数据,重点看三个地方:

  • Elapsed Time:多跳传递路径涉及多层 Join 与递归关联,IM 的向量化过滤通常能明显缩短响应时间。
  • 逻辑读与物理读:走 IM 扫描时 Consistent Gets 显著下降,且不占用传统 Buffer Cache 资源。
  • IM 相关统计项:可以通过统计项 IM scan CUs pruned 查看被 IM Storage Index 裁剪跳过的 IMCU 数量,而 IM scan rows 表示实际扫描读取的行数。

本次测试中,开启 IM 后逻辑读从约 689 万降到约 61 万,差距非常直观。

关注我,和AI一起成长~