索引是数据库性能优化的核心。合理的索引能让查询快几个数量级,但索引过多也会影响写入性能。
模型中定义索引:
type User struct {
ID uint
Name string `gorm:"index"`
Email string `gorm:"uniqueIndex"`
}
AutoMigrate 时自动创建:
db.AutoMigrate(&User{})
默认索引名是 idx_表名_字段名。自定义索引名:
type User struct {
Name string `gorm:"index:idx_name"`
}
多字段组合索引:
type User struct {
Name string `gorm:"index:idx_name_city"`
City string `gorm:"index:idx_name_city"`
}
指定顺序:
type User struct {
Name string `gorm:"index:idx_name_city,priority:1"`
City string `gorm:"index:idx_name_city,priority:2"`
}
优先级数字越小越靠前。
type User struct {
Email string `gorm:"uniqueIndex"`
}
复合唯一索引:
type User struct {
Name string `gorm:"uniqueIndex:idx_name_department"`
Dept string `gorm:"uniqueIndex:idx_name_department"`
}
部分数据库支持条件索引:
type User struct {
Status string `gorm:"index:idx_active,option:WHERE status = 'active'"`
}
PostgreSQL 支持,MySQL 不支持。
type Article struct {
Title string `gorm:"type:varchar(255);index:idx_fulltext,type:FULLTEXT"`
Content string `gorm:"type:text;index:idx_fulltext,type:FULLTEXT"`
}
MySQL 支持。
db.Migrator().CreateIndex(&User{}, "Name")
db.Migrator().CreateIndex(&User{}, "idx_name")
db.Migrator().DropIndex(&User{}, "Name")
db.Migrator().DropIndex(&User{}, "idx_name")
if db.Migrator().HasIndex(&User{}, "idx_name") {
db.Migrator().DropIndex(&User{}, "idx_name")
}
复杂索引用原生 SQL:
db.Exec(`CREATE INDEX idx_user_name ON users(name)`)
db.Exec(`CREATE UNIQUE INDEX idx_user_email ON users(email)`)
db.Exec(`
CREATE INDEX idx_user_name_city
ON users(name, city)
`)
db.Exec(`
CREATE INDEX idx_user_created
ON users(created_at DESC)
`)
PostgreSQL 条件索引:
db.Exec(`
CREATE INDEX idx_active_users
ON users(email)
WHERE status = 'active'
`)
B-Tree 索引
默认类型,适合等值查询和范围查询:
Name string `gorm:"index"`
Hash 索引
只支持等值查询,某些数据库支持:
db.Exec(`CREATE INDEX idx_user_name_hash ON users USING HASH (name)`)
全文索引
文本搜索:
db.Exec(`CREATE FULLTEXT INDEX idx_article_content ON articles(content)`)
何时创建索引
何时不创建索引
复合索引原则
最左前缀原则:索引 (a, b, c) 可以用于:
WHERE a = ?WHERE a = ? AND b = ?WHERE a = ? AND b = ? AND c = ?不能用于:
WHERE b = ?WHERE c = ?把最常用的查询条件放在最左边。
慢查询分析
EXPLAIN SELECT * FROM users WHERE name = '张三';
查看是否使用索引。
强制使用索引
db.Clauses(clause.UseIndex("idx_name")).Find(&users)
忽略索引
db.Clauses(clause.IgnoreIndex("idx_name")).Find(&users)
用户表索引
type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"index:idx_name_city;size:50"`
City string `gorm:"index:idx_name_city;size:50"`
Email string `gorm:"uniqueIndex;size:100"`
Phone string `gorm:"uniqueIndex:idx_phone;size:20"`
Status string `gorm:"index;size:20"`
CreatedAt time.Time `gorm:"index"`
}
订单表索引
type Order struct {
ID uint `gorm:"primaryKey"`
UserID uint `gorm:"index"`
Status string `gorm:"index:idx_status_created"`
CreatedAt time.Time `gorm:"index:idx_status_created"`
Amount float64
}
// 复合索引:按状态和时间查询
// SELECT * FROM orders WHERE status = 'paid' ORDER BY created_at DESC
文章表索引
type Article struct {
ID uint `gorm:"primaryKey"`
Title string `gorm:"index:idx_fulltext,type:FULLTEXT"`
Content string `gorm:"index:idx_fulltext,type:FULLTEXT"`
AuthorID uint `gorm:"index"`
Status string `gorm:"index:idx_status_published"`
PublishedAt *time.Time `gorm:"index:idx_status_published"`
}
索引是性能优化的利器,但要用对地方。理解索引原理,遵循最左前缀原则,定期检查慢查询。