Initial commit
This commit is contained in:
208
skills/hyperindex-development/references/database-indexes.md
Normal file
208
skills/hyperindex-development/references/database-indexes.md
Normal file
@@ -0,0 +1,208 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user