索引机制 #
一、索引概述 #
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