Files
gh-enviodev-envio-plugins-p…/skills/hyperindex-development/references/database-indexes.md
2025-11-29 18:26:05 +08:00

209 lines
3.8 KiB
Markdown

# Database Indexes & Query Optimization
Optimize query performance with strategic indexing.
## Why Indexes Matter
| Data Size | Without Indexes | With Indexes |
|-----------|-----------------|--------------|
| 1,000 rows | ~10ms | ~1ms |
| 100,000 rows | ~500ms | ~2ms |
| 1,000,000+ rows | 5+ seconds | ~5ms |
## Single-Column Indexes
Use `@index` directive on frequently queried fields:
```graphql
type Transaction {
id: ID!
userAddress: String! @index
tokenAddress: String! @index
amount: BigInt!
timestamp: BigInt! @index
}
```
**Use when:**
- Frequently filter by a field
- Sort results by a field
- Field has many different values (high cardinality)
## Composite Indexes
For multi-field queries, use entity-level `@index`:
```graphql
type Transfer @index(fields: ["from", "to", "tokenId"]) {
id: ID!
from: String! @index
to: String! @index
tokenId: BigInt!
value: BigInt!
timestamp: BigInt!
}
```
Creates:
1. Individual indexes on `from` and `to`
2. Composite index on `from + to + tokenId`
**Use when:**
- Query multiple fields together
- "Find transfers from X to Y for token Z"
## Multiple Composite Indexes
```graphql
type NFTListing
@index(fields: ["collection", "status", "price"])
@index(fields: ["seller", "status"]) {
id: ID!
collection: String! @index
tokenId: BigInt!
seller: String! @index
price: BigInt!
status: String! @index # "active", "sold", "cancelled"
createdAt: BigInt! @index
}
```
Supports:
- Active listings for collection, sorted by price
- Listings by seller with status
- Recently created listings
## Automatic Indexes
HyperIndex auto-indexes:
- All `ID` fields
- All `@derivedFrom` fields
No manual indexing needed for these.
## Common Index Patterns
### Token Transfers
```graphql
type TokenTransfer {
id: ID!
token_id: String! @index
from: String! @index
to: String! @index
amount: BigInt!
blockNumber: BigInt! @index
timestamp: BigInt! @index
}
```
### DEX Swaps
```graphql
type Swap @index(fields: ["pair", "timestamp"]) {
id: ID!
pair_id: String! @index
sender: String! @index
amountIn: BigInt!
amountOut: BigInt!
timestamp: BigInt! @index
}
```
### User Activity
```graphql
type UserAction @index(fields: ["user", "actionType", "timestamp"]) {
id: ID!
user: String! @index
actionType: String! @index
timestamp: BigInt! @index
amount: BigInt!
}
```
## Performance Tradeoffs
### Write Impact
| Index Level | Write Slowdown | Read Speed |
|-------------|----------------|------------|
| No indexes | Baseline | Slowest |
| Few targeted | 5-10% | Fast |
| Many indexes | 15%+ | Fastest |
Blockchain data is read-heavy - indexes usually worth it.
### Storage
- Each index: 2-10 bytes per row
- Consider for very large tables (millions+ rows)
## Query Optimization Tips
### Fetch Only What You Need
```graphql
# Good
query {
Transfer(where: { token: { _eq: "0x123" } }, limit: 10) {
id
amount
}
}
# Bad - unnecessary fields
query {
Transfer(where: { token: { _eq: "0x123" } }, limit: 10) {
id
from
to
amount
timestamp
blockNumber
transactionHash
# ... more fields
}
}
```
### Always Paginate
```graphql
query {
Transfer(
where: { token: { _eq: "0x123" } }
limit: 20
offset: 40 # Page 3
) {
id
amount
}
}
```
### Filter on Indexed Fields
```graphql
# Fast - userAddress is indexed
query {
Transaction(where: { userAddress: { _eq: "0x..." } }) { ... }
}
# Slow - amount is not indexed
query {
Transaction(where: { amount: { _gt: "1000" } }) { ... }
}
```
## Index Checklist
When designing schema:
- [ ] Index fields used in `where` clauses
- [ ] Index fields used in `order_by`
- [ ] Add composite indexes for multi-field queries
- [ ] Consider cardinality (high variety = good index candidate)
- [ ] Don't over-index write-heavy entities
- [ ] Test query performance with realistic data volumes