Oracle 索引深度解析(从内部原理到实战案例)

Oracle 索引深度解析(从内部原理到实战案例)

索引是数据库性能优化的核心手段之一。理解 Oracle 索引的内部工作原理,是写出高效 SQL、解决性能问题的基本功。本文将从索引的基本概念出发,深入 B-tree 索引的内部结构,并通过一个完整的实战案例,带你全面掌握 Oracle 索引的原理与使用。


一、索引概述

1.1 什么是索引?

索引是一种与表或表簇相关联的可选结构 ,用于提高数据访问速度。可以把它想象成一本书的目录:没有目录时,你要找某个知识点只能一页一页翻;有了目录,直接定位到目标页码即可。

在数据库中,如果一张堆组织表(Heap Table)没有索引,数据库必须执行全表扫描 才能找到特定值。例如,在 hr.departments 表中查找 location_id = 2700 的部门,数据库需要扫描每一个表块中的每一行。当数据量增大时(假设10G大小),这种做法的性能就会急剧下降。

1.2 索引的核心特征

索引有以下几个关键特征:

特征 说明
独立性 索引在逻辑上和物理上都与表相互独立。删除或创建索引不会影响表本身
透明性 索引的存在与否不影响 SQL 语句的写法
自动维护 数据库自动维护索引,DML 操作时自动更新
代价权衡 索引提升查询性能,但会降低 DML 性能,因为每次插入、更新、删除都需要维护索引

1.3 何时应该创建索引?

通常在以下情况下考虑创建索引:

  • 索引列经常被查询 ,且只返回表中的一小部分数据行
  • 存在引用完整性约束(如外键),索引可以避免父表操作时的全表锁定
  • 需要设置唯一键约束,并希望手动指定索引选项
  • 建索引时自动收集(Oracle 10g+ 默认行为),这个默认行为由一个名为 _optimizer_compute_index_stats 的隐含参数控制

二、Oracle B-tree 索引的内部原理

B-tree(Balanced Tree,平衡树)是 Oracle 中最常用的索引类型。这里的 "B" 代表 Balanced(平衡),而不是 Binary(二叉)。

2.1 B-tree 索引的三大组件

B-tree 索引是一种典型的树形结构,从根节点到任何一个叶子节点的路径都是等距离的。它由以下三部分组成:

(1)根节点(Root Node)
  • 每个 B-tree 索引有且只有一个根节点
  • 它是位于树最顶端的分支节点
  • 存储指向下一层分支节点的指针和最小键值信息
(2)分支节点(Branch Node)
  • 存储指针,指向其他的分支节点或叶子节点
  • 每个索引条目包含两个字段:
    • 最小键值 :该分支下所指向的索引块中包含的最小键值(分支块中的键值 K 指向子块 C,则子块 C 中所有键值 ≥ K)
    • 块地址:4 字节,指向下一层索引块的地址
  • 分支节点能容纳的记录数由数据块大小 和索引键值长度共同决定
  • 分支块中除了常规条目外,还有一个特殊指针------LMC(Left Most Child,最左子节点指针) ,它指向的子块中所有键值严格小于分支块中任何条目的键值。
  • 导航逻辑:查找值 ≥ 键值 → 进入该子块
  • 最左子块导航逻辑:通过 LMC 指针,存储所有小于最小分隔键的值(根节点也包含LMC指针)
  • 前缀压缩:进一步节省空间,使分支节点可以容纳更多条目。分支块中存储的键值不一定是完整键值,Oracle 可能只存储前缀 ,只要能够区分不同子块的键值范围即可,例如,对于键值 ABCDEF 和 ABCXYZ,分支块可能只存储 ABCD 和 ABCX 作为分隔键。
(3)叶子节点(Leaf Node)
  • 位于树的最底层
  • 存储完整的索引条目,直接指向表中的数据行
  • 每个索引条目包含:
    • 索引键值(单列或多列组合)
    • ROWID:数据行在表中的物理地址
  • 叶子节点之间通过双向链表连接,支持高效的范围扫描

下图展示了 B-tree 索引的逻辑结构:

复制代码
                    ┌─────────────┐
                    │   Root Node │
                    │  (1, B1)    │
                    │  (100, B2)  │
                    │  (200, B3)  │
                    └──────┬──────┘
                           │
          ┌────────────────┼────────────────┐
          ▼                ▼                ▼
    ┌───────────┐   ┌───────────┐   ┌───────────┐
    │ Branch B1 │   │ Branch B2 │   │ Branch B3 │
    │ (1, L1)   │   │ (100, L3) │   │ (200, L5) │
    │ (50, L2)  │   │ (150, L4) │   │ (250, L6) │
    └─────┬─────┘   └─────┬─────┘   └─────┬─────┘
          │               │               │
    ┌─────┴─────┐   ┌─────┴─────┐   ┌─────┴─────┐
    ▼           ▼   ▼           ▼   ▼           ▼
  ┌────┐     ┌────┐ ┌────┐     ┌────┐ ┌────┐     ┌────┐
  │ L1 │◄───►│ L2 │ │ L3 │◄───►│ L4 │ │ L5 │◄───►│ L6 │
  │(2) │     │(51)│ │(120│     │(151│ │(249│     │(251│
  └────┘     └────┘ └────┘     └────┘ └────┘     └────┘
                   叶子节点(双向链表)

2.2 索引的物理存储

创建索引时,Oracle 自动分配一个索引段(Index Segment) 来存储索引数据。索引段可以与表段存放在不同的表空间,甚至可以放在不同的物理磁盘上以提高 I/O 并行度。

索引块内部的数据存储有以下几个关键点:

(1)索引块内的数据不是按键值顺序物理存储的

索引块体(Block Body)像表一样以堆(Heap)方式存储索引条目。例如,先插入键值 10,再插入键值 0,0 可能被放在 10 的上面。

(2)行目录(Row Directory)维护逻辑顺序

对于索引块,行目录中的槽位是按索引键值有序排列的,继续上面的例子,行目录如下

复制代码
行目录(Row Directory):
  slot 0 → 指向键值=0 的条目(偏移地址 B)
  slot 1 → 指向键值=10 的条目(偏移地址 A)

虽然块体中的数据不是物理有序的,但行目录按键值顺序存储了指向各条记录的指针。

因此,当执行索引扫描时,Oracle 按行目录的顺序依次读取条目 ,实际访问顺序是 0 → 10,逻辑上是有序的。

备注:Row Directory和Row Header是同一个东西,不同的称呼而已!

(3)为什么这样设计?

这个设计是写入性能与读取性能之间的精妙平衡:

设计选择 写入性能 读取性能
物理有序存储(每次插入都排序移动) 差------需要频繁移动数据 好
堆式存储 + 行目录排序(Oracle 的做法) 好------直接追加到空闲空间 好------通过行目录按序访问

如果每次插入都维护物理有序,那每次插入都可能触发大量数据移动,写入开销极高。堆式存储让插入操作只需找到空闲位置直接写入,而行目录的排序维护开销极小(只是调整指针数组),从而同时保证了高效的写入和高效的有序读取。

(4)唯一索引与非唯一索引的差异

  • 唯一索引:每个键值对应一个 ROWID
  • 非唯一索引:Oracle 将 ROWID 作为额外列追加到键值后面,使每个索引条目唯一。排序时先按键值排序,再按 ROWID 升序排序

2.3 B-tree 索引的检索过程

当执行一个使用索引的查询时,Oracle 的检索过程如下:

  1. 从根节点开始,根据查询条件中的键值,找到对应的分支节点
  2. 逐层向下,在分支节点中通过比较键值确定下一层的索引块
  3. 到达叶子节点,读取索引条目中的键值和 ROWID
  4. 通过 ROWID 回表读取完整的数据行

整个过程的时间复杂度为 O(log n) ,与索引的高度(Height)成正比。B-tree 索引的一个核心优势是:所有叶子节点的深度相同,因此无论查询什么键值,访问速度基本相同。

2.4 索引的分裂与维护

当向表中插入新数据时,如果对应的叶子节点已满,Oracle 会执行索引块分裂(Block Split) 操作:

  • 叶子节点满 → 分裂出新的叶子节点
  • 分支节点满 → 分裂出新的分支节点

这正是索引在 DML 操作中产生额外开销的原因。频繁的插入操作可能导致索引碎片化,降低查询效率。此时可以通过 ALTER INDEX ... COALESCE 合并索引碎片,或通过 ALTER INDEX ... REBUILD 重建索引来优化。

2.5 B-tree 索引的子类型

Oracle 的 B-tree 索引有以下几种子类型:

类型 特点 适用场景
索引组织表(IOT) 数据按主键顺序以 B-tree 结构存储,索引即数据 OLAP、信息获取系统
B-tree 聚簇索引 一个聚簇键指向一个块,包含多行数据 按聚簇键频繁访问多行
降序索引 键值按降序存储,避免 ORDER BY DESC 时的排序开销 需要降序排序的查询
反向键索引 键值字节反转存储,分散热点块竞争 RAC 环境、序列值列,不适用于范围扫描

三、深入理解索引的关键指标

3.1 聚簇因子(Clustering Factor)

聚簇因子反映了通过索引扫描访问表时需要访问的表数据块数量,是优化器评估索引扫描成本的重要指标。

其计算方式为:顺序扫描索引条目,比较相邻两个条目的 ROWID,如果属于不同的数据块,则聚簇因子加 1。

  • 聚簇因子越低,说明索引顺序与表数据存储顺序越一致,索引扫描效率越高
  • 聚簇因子越高,说明索引顺序与表数据存储顺序差异越大,回表 I/O 越多

3.2 索引高度(Height)与 BLEVEL

索引的 BLEVEL 表示从根节点到叶子节点的层级深度(根节点为第 0 层),索引高度 HEIGHT = BLEVEL + 1。

sql 复制代码
-- 查看索引的 BLEVEL
SELECT INDEX_NAME, BLEVEL 
FROM DBA_INDEXES 
WHERE INDEX_NAME = '你的索引名';

索引高度直接影响查询性能:高度为 2 的索引,最多只需 3 次 I/O(根节点 + 分支节点 + 叶子节点)即可定位到数据。

3.3 索引的可见性与可用性

Oracle 提供了两种控制索引"存在感"的属性:

  • 可用性(Usability) :USABLE(默认)或 UNUSABLE。不可用索引在 DML 中不被维护,优化器忽略它。适合大批量数据加载时临时禁用索引
  • 可见性(Visibility) :VISIBLE(默认)或 INVISIBLE。不可见索引在 DML 中仍被维护,但优化器默认不使用它。适合在删除索引前测试影响
sql 复制代码
-- 创建不可见索引
CREATE INDEX idx_name ON table_name(col) INVISIBLE;

-- 调整可见性
ALTER INDEX idx_name INVISIBLE;
ALTER INDEX idx_name VISIBLE;

3.4 索引的压缩

Oracle 的索引压缩技术主要分为两大类:索引键压缩(Index Key Compression,即传统前缀压缩) 和高级索引压缩(Advanced Index Compression)

索引键压缩 (Index Key Compression)

这是从 Oracle 8i 时代就有的经典压缩方式,也叫前缀压缩 。它的核心思想是:在每个索引叶子块内部,将重复出现的索引列前缀值只存储一次。

  • 工作原理 :假设一个索引建立在 (A, B, C) 三列上。压缩时会将索引键拆分为前缀 (Prefix) 和后缀 (Suffix)。

    • 前缀 :由前面连续的几列组成(如 A,或 A, B),这部分重复的值在块内只存一次。
    • 后缀 :剩余列和 ROWID 组成,每条索引记录分别存储,但会引用其对应的前缀。
      例如,对于索引值 (online, 0, rowid1)、(online, 0, rowid2),前缀 (online, 0) 会被提取出来存储一次。
  • 适用场景与注意事项:

    • 它只适用于B-tree索引。
    • 对于非唯一索引 ,前缀可以包含所有索引列;对于唯一索引 ,前缀列数必须小于总列数。
    • 单列唯一索引无法使用此压缩。
    • 最适合索引前导列重复值很高的场景。
  • 如何启用?

    可以在 CREATE INDEX 或 ALTER INDEX ... REBUILD 时指定 COMPRESS 关键字及压缩的前缀列数。

    复制代码
    -- 压缩前2列作为前缀
    CREATE INDEX idx_emp_dept_sal ON employees(department_id, job_id, salary) COMPRESS 2;
    
    -- 重建现有索引并启用压缩
    ALTER INDEX idx_emp_dept_sal REBUILD COMPRESS 2;

    如果不指定数字,Oracle 会使用默认值:非唯一索引默认压缩所有列,唯一索引默认压缩除最后一列外的所有列。

高级索引压缩 (Advanced Index Compression)

这是 Oracle 12c 引入的新一代 压缩技术。它不要求用户了解数据分布,Oracle 会在每个数据块内部 ,通过多种算法自动选择最优的压缩策略,实现了自适应的压缩。

  • 工作原理与优势:

    • 相比前缀压缩,它能提供更高的压缩率,对更多类型的索引都有效。
    • 压缩和解压的CPU开销更低。
    • 无需人工指定前缀列数,大大降低了使用门槛。
    • 对唯一索引和非唯一索引都适用。
  • 两种压缩级别:

    • COMPRESS ADVANCED LOW :提供较低的压缩率,但CPU开销也最小。需要数据库兼容性级别为 12.1.0 或更高。
    • COMPRESS ADVANCED HIGH :提供更高的压缩率,CPU开销也相应更高。这是默认 级别,需要数据库兼容性级别为 12.2.0 或更高。
  • 如何启用?

    复制代码
    -- 使用高级压缩(默认HIGH级别)
    CREATE INDEX idx_emp_dept_sal ON employees(department_id, job_id, salary) COMPRESS ADVANCED;
    
    -- 显式指定LOW级别
    CREATE INDEX idx_emp_dept_sal ON employees(department_id, job_id, salary) COMPRESS ADVANCED LOW;
    
    -- 重建现有索引并启用高级压缩
    ALTER INDEX idx_emp_dept_sal REBUILD COMPRESS ADVANCED HIGH;

3.5 索引列与空值

在 Oracle 的 B-tree 索引中,只有当索引的所有列都为 NULL 时,该行的索引条目才不会被存储。

  • 单列索引 :索引只有一列,如果该列值为 NULL,整行就不会被索引,因此 WHERE column IS NULL 无法利用索引。
  • 复合索引 :只要索引中至少有一个列的值不为 NULL,该行就会被记录在索引中。

因此,要查询 NULL 值,核心思路就是为索引添加一个永不为 NULL 的列

方法一:复合索引(添加常量列)
复制代码
-- 创建包含常量的复合索引
CREATE INDEX idx_people_idnum ON xx_people(id_number, 1);

或者
-- 创建包含常量的复合索引
CREATE INDEX idx_people_idnum ON xx_people(1,id_number);
方法二:使用**虚拟列(Virtual Column)**的方式
复制代码
-- 使用虚拟列(Oracle 11g+)
ALTER TABLE t ADD (null_marker GENERATED ALWAYS AS (1) VIRTUAL);
CREATE INDEX idx_t ON t(null_marker, column_name);

虚拟列是 Oracle 11g 引入的特性,它是一种不实际存储在磁盘上的特殊列,其值在查询时由表达式实时计算得出。在逻辑上,它和普通列具有相同的语法能力------可以出现在 SELECT、WHERE 中,可以建索引、建约束、做分区键。
虚拟列的定义表达式存储在数据字典中(USER_TAB_COLUMNS 的 DATA_DEFAULT 字段),而不存储实际数据。每当你查询该列时,Oracle 实时计算表达式的值。
语法:
column_name [datatype] [GENERATED ALWAYS] AS (expression) [VIRTUAL]
其中:
GENERATED ALWAYS 和 VIRTUAL 都是可选关键字,写了更明确
expression 是计算表达式,可以引用同表的其他列、常量、内置函数,甚至用户自定义的确定性(DETERMINISTIC)函数

四、案例:从 SQL 优化到索引设计

4.1 场景描述

假设我们有一个电商订单表 orders,包含以下结构:

sql 复制代码
CREATE TABLE orders (
    order_id      NUMBER PRIMARY KEY,
    customer_id   NUMBER NOT NULL,
    order_date    DATE NOT NULL,
    total_amount  NUMBER(10,2),
    status        VARCHAR2(20),
    region        VARCHAR2(50),
    created_at    DATE DEFAULT SYSDATE
);

-- 插入 500 万条测试数据
BEGIN
    FOR i IN 1..5000000 LOOP
        INSERT INTO orders VALUES (
            i,
            TRUNC(DBMS_RANDOM.VALUE(1, 100000)),
            SYSDATE - TRUNC(DBMS_RANDOM.VALUE(0, 730)),
            ROUND(DBMS_RANDOM.VALUE(10, 10000), 2),
            CASE TRUNC(DBMS_RANDOM.VALUE(1, 5))
                WHEN 1 THEN 'PENDING'
                WHEN 2 THEN 'PAID'
                WHEN 3 THEN 'SHIPPED'
                WHEN 4 THEN 'COMPLETED'
            END,
            CASE TRUNC(DBMS_RANDOM.VALUE(1, 5))
                WHEN 1 THEN 'EAST'
                WHEN 2 THEN 'WEST'
                WHEN 3 THEN 'NORTH'
                WHEN 4 THEN 'SOUTH'
            END,
            SYSDATE - TRUNC(DBMS_RANDOM.VALUE(0, 365))
        );
    END LOOP;
    COMMIT;
END;
/

-- 收集统计信息
EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'ORDERS');

4.2 问题 SQL

业务中有一个高频查询:查询某个客户在指定日期范围内的所有订单,按订单日期降序排列。

sql 复制代码
SELECT order_id, order_date, total_amount, status, region
FROM orders
WHERE customer_id = 12345
  AND order_date BETWEEN DATE '2025-01-01' AND DATE '2025-12-31'
ORDER BY order_date DESC;

执行计划分析

我们先查看该 SQL 当前的执行计划:

sql 复制代码
set autotrace on
SELECT order_id, order_date, total_amount, status, region
FROM orders
WHERE customer_id = 12345
  AND order_date BETWEEN DATE '2025-01-01' AND DATE '2025-12-31'
ORDER BY order_date DESC;
set autotrace off

Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
      34590  consistent gets          ----逻辑读34590个块
          0  physical reads

在没有合适索引的情况下,执行计划显示为 全表扫描(TABLE ACCESS FULL) ,需要扫描 500 万行数据,逻辑读达到34590个块。

4.3 索引方案分析与设计

方案一:单列索引

如果只在 customer_id 上创建索引:

sql 复制代码
CREATE INDEX idx_orders_customer ON orders(customer_id);

-- 优化后效果
set autotrace on
SELECT order_id, order_date, total_amount, status, region
FROM orders
WHERE customer_id = 12345
  AND order_date BETWEEN DATE '2025-01-01' AND DATE '2025-12-31'
ORDER BY order_date DESC;
set autotrace off

Statistics
----------------------------------------------------------
          5  recursive calls
          0  db block gets
        144  consistent gets           ---逻辑读下降至144个!
          2  physical reads
  • 索引可以快速定位到 customer_id = 12345 的所有行
  • 但还需要在结果集中过滤 order_date 范围,并且排序 order_date DESC
  • 如果该客户的订单量很大(假设有 10 万条),仍然需要扫描大量数据
方案二:复合索引(推荐)

在 customer_id 和 order_date 上创建复合索引,并指定降序:

sql 复制代码
CREATE INDEX idx_orders_cust_date ON orders(customer_id, order_date DESC);

-- 优化效果,本次索引,只会减少排序的消耗,逻辑读基本不会有变化

为什么这个索引有效?

复合索引的列顺序至关重要:

  1. 前导列 customer_id:WHERE 条件精确匹配,可以快速定位到该客户的所有索引条目
  2. 第二列 order_date DESC :索引本身已经按 order_date 降序排列,查询中的 ORDER BY order_date DESC 可以直接利用索引的有序性,完全避免排序操作
  3. 索引条目中包含了 customer_id 和 order_date,Oracle 可以通过索引范围扫描(Index Range Scan) 快速定位到符合条件的行
方案三:覆盖索引(进一步优化)

如果查询只需要索引中的列,可以创建覆盖索引(Covering Index) ,完全避免回表:

sql 复制代码
CREATE INDEX idx_orders_covering ON orders(customer_id, order_date DESC, total_amount, status, region);

-- 优化后效果
set autotrace on
SELECT order_id, order_date, total_amount, status, region
FROM orders
WHERE customer_id = 12345
  AND order_date BETWEEN DATE '2025-01-01' AND DATE '2025-12-31'
ORDER BY order_date DESC;
set autotrace off

Plan hash value: 2217659197

---------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                     |    25 |   950 |    28   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| ORDERS              |    25 |   950 |    28   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IDX_ORDERS_COVERING |    25 |       |     3   (0)| 00:00:01 |

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
         58  consistent gets        --逻辑读进一步下降至58个块
          0  physical reads

但需要注意:索引列越多,维护成本越高,存储空间越大。需要权衡查询性能与 DML 开销。

4.4 通过数据字典分析索引使用情况

sql 复制代码
-- 查看索引的基本信息
SELECT INDEX_NAME, INDEX_TYPE, UNIQUENESS, BLEVEL, LEAF_BLOCKS, DISTINCT_KEYS
FROM USER_INDEXES
WHERE TABLE_NAME = 'ORDERS';

-- 查看索引列信息
SELECT INDEX_NAME, COLUMN_NAME, COLUMN_POSITION, DESCEND
FROM USER_IND_COLUMNS
WHERE TABLE_NAME = 'ORDERS'
ORDER BY INDEX_NAME, COLUMN_POSITION;

-- 查看索引的聚簇因子(评估回表效率)
SELECT INDEX_NAME, CLUSTERING_FACTOR, LEAF_BLOCKS, DISTINCT_KEYS
FROM USER_INDEXES
WHERE TABLE_NAME = 'ORDERS';

4.6 索引监控与维护

sql 复制代码
-- 监控索引是否被使用(需要先开启监控)
ALTER INDEX idx_orders_cust_date MONITORING USAGE;

-- 一段时间后查看使用情况
SELECT * FROM V$OBJECT_USAGE WHERE INDEX_NAME = 'IDX_ORDERS_CUST_DATE';

-- 关闭监控
ALTER INDEX idx_orders_cust_date NOMONITORING USAGE;

如果发现索引长期未被使用,或者聚簇因子过高导致索引扫描成本超过全表扫描,可以考虑删除 或重建索引。


五、索引使用的最佳实践

5.1 复合索引的列顺序

复合索引的列顺序至关重要:

  • 将最常被访问 、选择性最高的列放在前面
  • 查询条件中必须包含前导列,索引才可能被使用
  • 例如 (last_name, job_id, salary) 的索引,查询只包含 job_id 时不会使用该索引

5.2 索引的选择性

  • B-tree 索引 适合基数高(重复值少)的列
  • 对于基数低 (如性别、状态等只有几个值的列),B-tree 索引效果不佳,应考虑位图索引(Bitmap Index),oltp不考虑位图索引!!

5.3 避免索引失效的常见场景

  • 在索引列上使用函数 (如 UPPER(name))会导致索引失效,可考虑函数索引(Function-Based Index)
  • 使用 LIKE '%keyword'(前导模糊)会导致索引失效
  • 隐式类型转换(如将 VARCHAR2 列与 NUMBER 比较)会导致索引失效

5.4 索引数量的权衡

表中索引数量保持适量。过多的索引会显著降低 DML 性能,因为每次插入、更新、删除都需要维护所有索引。


六、总结

Oracle 索引是性能优化的核心工具,理解其内部原理是高效使用的前提:

核心概念 关键要点
B-tree 结构 根节点 → 分支节点 → 叶子节点(双向链表),所有叶子等深
索引条目 键值 + ROWID,非唯一索引将 ROWID 作为额外列
索引顺序 索引本身是有序结构,可避免 ORDER BY 排序
聚簇因子 反映索引顺序与表数据顺序的一致性,影响回表 I/O
复合索引 列顺序至关重要,前导列必须出现在 WHERE 条件中

索引是一把双刃剑------用得好,查询性能飞跃;用不好,DML 性能受损、存储空间浪费。

相关推荐
Yyyyyy~2 小时前
[Mysql] 数据类型
数据库·mysql
FITA阿泽要努力2 小时前
第 1 周·第 3 讲|工具如何交给模型:工具定义、参数与结构化调用
服务器·数据库·python·agent
需要8262 小时前
缓存与数据库一致性:延迟双删与订阅 binlog 的取舍
数据库·缓存
眼不痛请看我3 小时前
Ubuntu_22.04_LTS虚拟机安装指南
linux·数据库·ubuntu
Omics Pro3 小时前
强生:以机理为中心!虚拟细胞世界模型
数据库·人工智能·python·深度学习·算法·机器学习·自然语言处理
java资料站3 小时前
四、Spring AIAlibaba · Tools(工具调用)
数据库·sql·spring
步行cgn3 小时前
Spring 事务传播行为详解
java·数据库·spring
anxiao_m3 小时前
跨地域大文件怎么传?2026主流传输软件实测对比
大数据·数据库·文件传输
Su米苏3 小时前
基于 Token 预算的上下文压缩控制器(Context Compaction Controller)
前端·数据库·人工智能