1. Концепция и применение Индекса

1.1 Что такое Индекс

Индекс - это структура данных, используемая в системе управления базами данных для ускорения операций извлечения данных. Его можно рассматривать как "справочник" в базе данных, позволяющий быстро находить данные в таблице данных, избегая полного сканирования таблицы и значительно улучшая эффективность запросов. В практических применениях корректное использование индексов может значительно повысить производительность базы данных.

1.2 Типы Индексов

Существует несколько типов индексов, каждый со своим собственным дизайном и оптимизацией для различных сценариев применения:

  • Индекс для одного поля: Индекс, который включает только одно поле, подходит для сценариев, зависящих от одного условия для быстрых запросов.
  • Композитный Индекс: Индекс, который включает несколько полей, обеспечивая оптимизацию для запросов, содержащих эти поля.
  • Уникальный Индекс: Гарантирует уникальность индексных полей, не позволяя существовать дублирующим значениям. Уникальные индексы могут быть как для одного поля, так и композитные.

2. Определение Индекса

2.1 Определение Индекса Поля

Создание индекса для одного поля включает установку индекса для определенного столбца таблицы данных, что можно сделать с помощью метода Fields. В следующем примере показано, как создать индекс для поля phone сущности User.

func (User) Fields() []ent.Field {
    return []ent.Field{
        field.String("phone"),
    }
}
func (User) Indexes() []ent.Index {
    // Создаем индекс для одного поля.
    return []ent.Index{
        index.Fields("phone"),
    }
}

В этом фрагменте кода поле phone проиндексировано, что позволяет системе использовать индекс для более быстрых поисков при запросах поля phone.

2.2 Определение Уникального Индекса

Уникальный индекс гарантирует уникальность данных в индексированных столбцах. Его можно создать, добавив метод Unique к полю. Ниже приведены примеры создания уникальных индексов для одного и нескольких полей.

Создание уникального индекса для одного поля:

func (User) Fields() []ent.Field {
    return []ent.Field{
        field.String("email").Unique(),
    }
}

В этом примере поле email определено как уникальное, гарантируя уникальность email каждого пользователя в базе данных.

Создание уникального индекса для комбинации нескольких полей:

func (User) Indexes() []ent.Index {
    return []ent.Index{
        // Создаем уникальный индекс для нескольких полей.
        index.Fields("first_name", "last_name").Unique(),
    }
}

Этот код задает композитный уникальный индекс для комбинации полей first_name и last_name, предотвращая появление записей с одинаковыми значениями в обоих полях.

2.3 Определение Композитного Индекса

Когда условия запроса включают несколько полей, в игру может вступить композитный индекс. Композитный индекс хранит данные в порядке, определенном в индексе. Порядок индекса имеет значительное влияние на производительность запроса, поэтому при определении композитного индекса порядок полей должен определяться на основе шаблона запроса.

Вот пример создания композитного индекса:

func (User) Indexes() []ent.Index {
    return []ent.Index{
        // Создаем композитный индекс с несколькими полями.
        index.Fields("country", "city"),
    }
}

В этом примере создается композитный индекс для полей country и city. Это означает, что при выполнении операций запроса, включающих эти два поля, база данных может быстро найти данные, удовлетворяющие условиям.

Композитный индекс не только ускоряет производительность запроса, но также поддерживает сортировку данных на основе индекса, обеспечивая более эффективную производительность извлечения данных. При проектировании композитного индекса часто размещают поля с более высокой выборочностью в начале индекса, чтобы оптимизатор базы данных мог лучше использовать индекс.

3. Индексы рёбер

Во фреймворке ent, индексы рёбер - это способ определения индексов через рёбра (отношения). Этот механизм обычно используется для обеспечения уникальности полей в конкретных отношениях. Например, если ваша модель базы данных включает в себя города и улицы, и каждое название улицы в пределах города должно быть уникальным, то можно использовать индексы рёбер для достижения этой цели.

// Файл ent/schema/street.go определяет схему сущности "Street".
type Street struct {
    ent.Schema
}

func (Street) Fields() []ent.Field {
    // Определение полей
    return []ent.Field{
        field.String("name"),
    }
}

func (Street) Edges() []ent.Edge {
    // Определение отношения ребром с сущностью "City", где улица принадлежит городу.
    return []ent.Edge{
        edge.From("city", City.Type).
            Ref("streets").
            Unique(),
    }
}

func (Street) Indexes() []ent.Index {
    // Создание уникального индекса через ребро для обеспечения уникальности названий улиц в одном и том же городе.
    return []ent.Index{
        index.Fields("name").
            Edges("city").
            Unique(),
    }
}

В этом примере мы создаём сущность Street и связываем её с сущностью City. Определяя индекс ребра в методе Indexes сущности Street, мы гарантируем уникальность названия каждой улицы в пределах города.

Глава 5: Расширенные параметры индексов

5.1 Полнотекстовые и хеш-индексы

Полнотекстовый индекс и хеш-индекс - два уникальных типа индексов в MySQL и PostgreSQL, и они используются для различных сценариев оптимизации запросов.

Полнотекстовый индекс обычно используется для поиска текстовых данных, особенно когда требуется выполнение сложных запросов, таких как поиск по соответствию слов. Обе базы данных MySQL и PostgreSQL поддерживают полнотекстовый индекс. Например, в MySQL вы можете определить полнотекстовый индекс следующим образом:

// Файл ent/schema/user.go определяет схему сущности "User".
func (User) Indexes() []ent.Index {
    // Создание полнотекстового индекса, используя категорию FULLTEXT в MySQL
    return []ent.Index{
        index.Fields("description").
            Annotations(entsql.IndexTypes(map[string]string{
                dialect.MySQL: "FULLTEXT",
            })),
    }
}

Хеш-индекс особенно подходит для запросов равенства и не поддерживает сортировку и запросы диапазона. В PostgreSQL можно использовать хеш-индекс следующим образом:

func (User) Indexes() []ent.Index {
    // Определение индекса типа HASH
    return []ent.Index{
        index.Fields("c4").
            Annotations(entsql.IndexType("HASH")),
    }
}

5.2 Частичные индексы и префиксы индексов

Частичный индекс - это тип индекса, который индексирует только строки в таблице, удовлетворяющие определенным условиям. В SQLite и PostgreSQL можно использовать ключевое слово WHERE для создания частичных индексов.

Например, определяя частичный индекс в PostgreSQL:

func (User) Indexes() []ent.Index {
    // Создание частичного индекса на поле "nickname", содержащего только строки, где "active" равно true
    return []ent.Index{
        index.Fields("nickname").
            Annotations(
                entsql.IndexWhere("active"),
            ),
    }
}

Префикс индекса особенно полезен для текстовых полей, особенно в MySQL. Он может сократить время создания индекса, уменьшить занимаемое индексом пространство и обеспечить хорошую производительность. Как показано ниже, для MySQL можно определить индекс с префиксом:

func (User) Indexes() []ent.Index {
    // Создание индекса с использованием префикса
    return []ent.Index{
        index.Fields("description").
            Annotations(entsql.Prefix(128)),
    }
}

5.3 Аннотации и настройка индексов

В ent, Annotations - это функция, которая позволяет разработчикам настраивать индексы. Вы можете определить тип индекса, установить правила сортировки и многое другое.

Например, следующий код демонстрирует, как указать правила сортировки столбцов в индексе:

func (User) Indexes() []ent.Index {
    return []ent.Index{
        // Использование аннотаций для определения правил сортировки столбцов в индексе
        index.Fields("c1", "c2", "c3").
            Annotations(entsql.DescColumns("c1", "c2")),
    }
}

Благодаря функции аннотаций разработчики могут гибко настраивать индексы для оптимизации производительности и структуры базы данных.