索引机制 #

一、索引概述 #

1.1 什么是索引 #

text
索引作用:
├── 加速查询
├── 支持排序
├── 实现唯一约束
├── 支持全文搜索
└── 提供查询入口

1.2 索引特点 #

text
FaunaDB索引特点:
├── 自动维护更新
├── 支持复合索引
├── 支持部分索引
├── 支持唯一约束
└── 支持绑定值

二、创建索引 #

2.1 基本创建 #

javascript
// 创建基本索引
CreateIndex({
  name: "users_by_email",
  source: Collection("users"),
  terms: [
    { field: ["data", "email"] }
  ]
})

2.2 索引配置选项 #

javascript
// 完整配置示例
CreateIndex({
  name: "orders_by_user_and_date",
  
  // 数据源
  source: Collection("orders"),
  
  // 查询条件字段
  terms: [
    { field: ["data", "userId"] }
  ],
  
  // 排序字段
  values: [
    { field: ["data", "createdAt"], order: "desc" },
    { field: ["ref"] }
  ],
  
  // 是否唯一
  unique: false,
  
  // 是否串行化
  serialized: true,
  
  // 权限
  permissions: {
    read: Role("user")
  },
  
  // 部分索引
  source: {
    collection: Collection("orders"),
    fields: {
      statusFilter: Query(
        Lambda("doc",
          Equals(Select(["data", "status"], Var("doc")), "active")
        )
      )
    }
  }
})

三、索引类型 #

3.1 简单索引 #

javascript
// 单字段索引
CreateIndex({
  name: "users_by_email",
  source: Collection("users"),
  terms: [
    { field: ["data", "email"] }
  ]
})

// 使用
Match(Index("users_by_email"), "tom@example.com")

3.2 复合索引 #

javascript
// 多字段索引
CreateIndex({
  name: "orders_by_user_and_status",
  source: Collection("orders"),
  terms: [
    { field: ["data", "userId"] },
    { field: ["data", "status"] }
  ]
})

// 使用
Match(
  Index("orders_by_user_and_status"),
  "user_001",
  "pending"
)

3.3 排序索引 #

javascript
// 带排序值的索引
CreateIndex({
  name: "products_by_price",
  source: Collection("products"),
  values: [
    { field: ["data", "price"], order: "asc" },
    { field: ["ref"] }
  ]
})

// 使用(返回按价格排序的结果)
Paginate(
  Match(Index("products_by_price_range")),
  { size: 10 }
)

3.4 唯一索引 #

javascript
// 唯一约束索引
CreateIndex({
  name: "users_by_email_unique",
  source: Collection("users"),
  terms: [
    { field: ["data", "email"] }
  ],
  unique: true
})

// 尝试创建重复email会失败
Create(Collection("users"), {
  data: { email: "existing@example.com" }
})
// Error: instance not unique

3.5 全文索引 #

javascript
// 创建全文索引
CreateIndex({
  name: "products_by_name_search",
  source: Collection("products"),
  terms: [
    { field: ["data", "name"] }
  ],
  source: {
    collection: Collection("products"),
    fields: {
      nameTokens: Query(
        Lambda("doc",
          LowerCase(Select(["data", "name"], Var("doc")))
        )
      )
    }
  }
})

四、索引字段 #

4.1 terms字段 #

text
terms用途:
├── 定义查询条件字段
├── 用于Match查询
├── 支持多个字段
└── 顺序重要
javascript
// terms示例
CreateIndex({
  name: "orders_by_user_status_date",
  source: Collection("orders"),
  terms: [
    { field: ["data", "userId"] },      // 第一个参数
    { field: ["data", "status"] }       // 第二个参数
  ]
})

// 查询时按顺序传参
Match(
  Index("orders_by_user_status_date"),
  "user_001",     // userId
  "pending"       // status
)

4.2 values字段 #

text
values用途:
├── 定义返回值排序
├── 支持升序/降序
├── 可以包含ref
└── 影响分页顺序
javascript
// values示例
CreateIndex({
  name: "orders_sorted_by_date",
  source: Collection("orders"),
  terms: [
    { field: ["data", "userId"] }
  ],
  values: [
    { field: ["data", "createdAt"], order: "desc" },  // 按日期降序
    { field: ["data", "total"], order: "desc" },      // 再按金额降序
    { field: ["ref"] }                                 // 最后是ref
  ]
})

4.3 绑定字段 #

javascript
// 使用绑定字段
CreateIndex({
  name: "products_by_category_name",
  source: {
    collection: Collection("products"),
    fields: {
      // 绑定计算字段
      categoryLower: Query(
        Lambda("doc",
          LowerCase(Select(["data", "category"], Var("doc")))
        )
      )
    }
  },
  terms: [
    { binding: "categoryLower" }
  ],
  values: [
    { field: ["data", "name"] },
    { field: ["ref"] }
  ]
})

五、使用索引查询 #

5.1 Match查询 #

javascript
// 基本Match
Match(Index("users_by_email"), "tom@example.com")

// 获取匹配的文档
Get(Match(Index("users_by_email"), "tom@example.com"))

// 分页查询
Paginate(Match(Index("all_users")), { size: 10 })

5.2 多条件查询 #

javascript
// 使用复合索引
Match(
  Index("orders_by_user_status_date"),
  "user_001",
  "pending"
)

// 范围查询(需要values)
Paginate(
  Range(
    Match(Index("products_by_price")),
    [10],    // 最小值
    [100]    // 最大值
  )
)

5.3 集合操作 #

javascript
// 并集
Union(
  Match(Index("users_by_role"), "admin"),
  Match(Index("users_by_role"), "moderator")
)

// 交集
Intersection(
  Match(Index("users_by_status"), "active"),
  Match(Index("users_by_department"), "engineering")
)

// 差集
Difference(
  Match(Index("all_users")),
  Match(Index("users_by_status"), "deleted")
)

六、索引管理 #

6.1 查看索引 #

javascript
// 获取索引信息
Get(Index("users_by_email"))

// 列出所有索引
Paginate(Indexes())

// 检查索引是否存在
Exists(Index("users_by_email"))

6.2 更新索引 #

javascript
// 更新索引(有限支持)
Update(Index("users_by_email"), {
  permissions: {
    read: Role("user")
  }
})

// 注意:terms和values不能修改
// 需要修改时,需要删除重建

6.3 删除索引 #

javascript
// 删除索引
Delete(Index("old_index"))

七、索引优化 #

7.1 索引设计原则 #

text
设计原则:
├── 根据查询模式设计
├── 避免过多索引
├── 合理使用复合索引
├── 考虑排序需求
└── 利用绑定字段

7.2 查询优化 #

javascript
// 使用索引覆盖查询
// 索引定义
CreateIndex({
  name: "users_email_name",
  source: Collection("users"),
  terms: [
    { field: ["data", "email"] }
  ],
  values: [
    { field: ["data", "name"] },    // 包含name
    { field: ["ref"] }
  ]
})

// 查询时可以直接获取name,无需Get
Map(
  Paginate(Match(Index("users_email_name"), "tom@example.com")),
  Lambda(["name", "ref"], {
    name: Var("name"),
    ref: Var("ref")
  })
)

7.3 部分索引 #

javascript
// 只索引特定条件的文档
CreateIndex({
  name: "active_users",
  source: {
    collection: Collection("users"),
    fields: {
      isActive: Query(
        Lambda("doc",
          Equals(Select(["data", "status"], Var("doc")), "active")
        )
      )
    }
  },
  terms: [
    { binding: "isActive" }
  ]
})

// 查询只返回active用户
Paginate(Match(Index("active_users"), true))

八、实际应用示例 #

8.1 用户索引 #

javascript
// 按email查询(唯一)
CreateIndex({
  name: "users_by_email",
  source: Collection("users"),
  terms: [
    { field: ["data", "email"] }
  ],
  unique: true
})

// 按状态查询
CreateIndex({
  name: "users_by_status",
  source: Collection("users"),
  terms: [
    { field: ["data", "status"] }
  ],
  values: [
    { field: ["data", "createdAt"], order: "desc" },
    { field: ["ref"] }
  ]
})

// 按部门查询
CreateIndex({
  name: "users_by_department",
  source: Collection("users"),
  terms: [
    { field: ["data", "departmentId"] }
  ]
})

8.2 订单索引 #

javascript
// 按用户查询订单
CreateIndex({
  name: "orders_by_user",
  source: Collection("orders"),
  terms: [
    { field: ["data", "userId"] }
  ],
  values: [
    { field: ["data", "createdAt"], order: "desc" },
    { field: ["ref"] }
  ]
})

// 按状态和时间范围查询
CreateIndex({
  name: "orders_by_status_date",
  source: Collection("orders"),
  terms: [
    { field: ["data", "status"] }
  ],
  values: [
    { field: ["data", "createdAt"] },
    { field: ["ref"] }
  ]
})

// 按金额范围查询
CreateIndex({
  name: "orders_by_total",
  source: Collection("orders"),
  values: [
    { field: ["data", "total"] },
    { field: ["ref"] }
  ]
})

8.3 产品索引 #

javascript
// 按分类查询
CreateIndex({
  name: "products_by_category",
  source: Collection("products"),
  terms: [
    { field: ["data", "categoryId"] }
  ],
  values: [
    { field: ["data", "name"] },
    { field: ["ref"] }
  ]
})

// 按价格范围查询
CreateIndex({
  name: "products_by_price",
  source: Collection("products"),
  values: [
    { field: ["data", "price"] },
    { field: ["data", "name"] },
    { field: ["ref"] }
  ]
})

// 按库存查询
CreateIndex({
  name: "products_in_stock",
  source: {
    collection: Collection("products"),
    fields: {
      inStock: Query(
        Lambda("doc",
          GT(Select(["data", "stock"], Var("doc")), 0)
        )
      )
    }
  },
  terms: [
    { binding: "inStock" }
  ]
})

九、索引限制 #

9.1 数量限制 #

text
索引限制:
├── 每个集合最多64个索引
├── 每个索引最多32个terms
├── 每个索引最多32个values
├── 绑定字段最多32个
└── 索引名称最长64字符

9.2 大小限制 #

text
大小限制:
├── 单个索引条目:64KB
├── terms值:最大8KB
├── values值:最大8KB
└── 绑定字段值:最大8KB

十、索引最佳实践 #

10.1 命名规范 #

text
命名建议:
├── 描述性名称
├── 包含查询字段
├── 使用下划线分隔
└── 示例:users_by_email, orders_by_user_status

10.2 性能建议 #

text
性能优化:
├── 根据查询模式创建索引
├── 避免创建不必要的索引
├── 使用复合索引减少索引数量
├── 利用values实现排序
└── 使用部分索引减少索引大小

10.3 维护建议 #

text
维护建议:
├── 定期审查索引使用情况
├── 删除未使用的索引
├── 监控索引大小
└── 优化复合索引顺序

十一、常见问题 #

11.1 索引不存在 #

javascript
// 安全检查索引
If(
  Exists(Index("users_by_email")),
  Match(Index("users_by_email"), "tom@example.com"),
  Abort("Index not found")
)

11.2 查询无结果 #

javascript
// 安全获取结果
Let(
  {
    result: Match(Index("users_by_email"), "tom@example.com")
  },
  If(
    Exists(Var("result")),
    Get(Var("result")),
    null
  )
)

11.3 唯一约束冲突 #

javascript
// 处理唯一约束
Let(
  {
    existing: Match(Index("users_by_email_unique"), "tom@example.com")
  },
  If(
    Exists(Var("existing")),
    Update(Select(["ref"], Get(Var("existing"))), {
      data: { name: "Updated Tom" }
    }),
    Create(Collection("users"), {
      data: { email: "tom@example.com", name: "New Tom" }
    })
  )
)

十二、总结 #

索引要点:

特性 说明
terms 查询条件字段
values 排序和返回字段
unique 唯一约束
binding 绑定计算字段
source 数据源配置

下一步,让我们学习创建文档!

最后更新:2026-03-27