代码改变世界

Oracle Property Graph 结合 In-Memory 的性能验证

2026-09-19 06:36  AlfredZhao  阅读(15)  评论(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一起成长~