Ответ
В Go индексы в базах данных создаются либо с помощью прямых SQL-запросов через пакет database/sql
, либо с использованием ORM (Object-Relational Mapper), такого как GORM.
1. Использование database/sql
(прямой SQL):
Это наиболее универсальный способ. Вы просто выполняете SQL-запрос CREATE INDEX
через метод Exec
.
package main
import (
"database/sql"
"fmt"
_ "github.com/lib/pq" // Пример драйвера PostgreSQL
)
func createIndex(db *sql.DB) error {
// Использование IF NOT EXISTS делает запрос идемпотентным
query := `CREATE INDEX IF NOT EXISTS idx_users_email ON users (email);`
_, err := db.Exec(query)
if err != nil {
return fmt.Errorf("ошибка при создании индекса: %w", err)
}
fmt.Println("Индекс idx_users_email успешно создан.")
return nil
}
2. Использование GORM (ORM):
GORM позволяет определять индексы с помощью тегов структуры или создавать их программно через Migrator
. GORM автоматически создает индексы, определенные в тегах, при вызове AutoMigrate
.
package main
import (
"gorm.io/gorm"
"gorm.io/driver/sqlite" // Пример драйвера SQLite
"fmt"
)
type User struct {
gorm.Model
Name string `gorm:"index"` // Простой индекс на поле Name
Email string `gorm:"index:idx_email,unique"` // Именованный уникальный индекс на поле Email
City string
Age int
}
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
// AutoMigrate создаст таблицу User и индексы, определенные в тегах.
db.AutoMigrate(&User{})
// Программное создание составного индекса (если не определен в тегах)
// Это полезно для более сложных индексов или когда вы хотите управлять ими отдельно.
err = db.Migrator().CreateIndex(&User{}, "City", "Age")
if err != nil {
fmt.Println("Ошибка при создании составного индекса:", err)
} else {
fmt.Println("Составной индекс на City и Age создан.")
}
// Программное создание уникального индекса (если не определен в тегах)
// Для уникальных индексов GORM v2 часто использует CreateConstraint
err = db.Migrator().CreateConstraint(&User{}, "idx_unique_name") // Предполагается, что "idx_unique_name" - это имя уникального индекса/констрейнта
if err != nil {
fmt.Println("Ошибка при создании уникального индекса:", err)
} else {
fmt.Println("Уникальный индекс на Name создан.")
}
}
Ключевые моменты об индексах:
- Ускорение поиска: Индексы значительно ускоряют операции чтения (SELECT), особенно при фильтрации (WHERE), сортировке (ORDER BY) и объединении таблиц (JOIN).
- Замедление записи: Операции записи (INSERT, UPDATE, DELETE) могут замедляться, так как при изменении данных необходимо также обновлять индексы.
- Пространство на диске: Индексы занимают дополнительное место на диске.
- Типы индексов: Бывают простые, составные (по нескольким полям), уникальные (гарантируют уникальность значений в поле/полях).
- Выбор полей: Индексы следует создавать на полях, которые часто используются в условиях поиска, сортировки или в качестве внешних ключей.