Транзакции
Транзакция — это последовательность одной или нескольких операций в базе данных, которая выполняется как единое целое. Цель транзакции — гарантировать, что все операции внутри нее либо завершатся успешно, либо не будут применены вообще. Это важный механизм для обеспечения целостности данных и согласованности.
Основные свойства транзакции — ACID:
- Атомарность (Atomicity): Транзакция либо полностью выполняется, либо не выполняется вовсе. Если в процессе выполнения произойдет ошибка, все изменения, сделанные в рамках транзакции, будут отменены (ролбэкнуты).
Пример: Если выполняется транзакция на перевод денег между двумя счетами, оба действия — списание с одного и зачисление на другой — должны произойти вместе. Если одно из них не удалось, второе также должно быть отменено. - Согласованность (Consistency): После завершения транзакции данные должны находиться в согласованном состоянии. Транзакция должна поддерживать целостность базы данных.
Пример: В реляционной базе данных транзакция, которая нарушает уникальность ключа или другие ограничения целостности (например, внешний ключ), не будет завершена. - Изоляция (Isolation): Транзакции, выполняющиеся одновременно, не должны влиять друг на друга. Это гарантирует, что изменения, сделанные одной транзакцией, не видны другим, пока транзакция не завершена.
Уровни изоляции:
- READ UNCOMMITTED: Транзакция может видеть изменения, сделанные незавершенными транзакциями (грязные чтения). Обычно не используется в PostgreSQL.
- READ COMMITTED: Транзакция видит только изменения, подтвержденные другими транзакциями (уровень по умолчанию в PostgreSQL).
- REPEATABLE READ: Транзакция видит одни и те же данные на протяжении всего ее выполнения, даже если другие транзакции вносят изменения.
- SERIALIZABLE: Самый строгий уровень изоляции. Транзакции выполняются так, как будто они выполняются последовательно, а не параллельно. - Долговечность (Durability): После того как транзакция завершена (закоммичена), её изменения сохраняются в базе данных, даже если произойдет сбой системы.
MVCC (Многоверсионное управление параллелизмом)
PostgreSQL использует модель MVCC для управления транзакциями, которая позволяет транзакциям не блокировать чтение и запись данных. При этом каждая транзакция видит "свой" снимок данных на момент начала транзакции. Это означает, что одна транзакция может обновлять строки, пока другие транзакции читают старые версии этих строк.
Этот подход позволяет улучшить параллелизм и производительность при работе с базой данных.
Индексы
Индексы — специальные объекты базы данных, предназначенные в основном для ускорения доступа к данным.
Основные типы индексов в PostgreSQL:
B-tree индексы (по умолчанию): наиболее часто используемый и универсальный тип индекса в PostgreSQL. Они подходят для большинства операций, включая:
- Операции сравнения (=, <, <=, >, >=).
- Сортировку данных по возрастанию или убыванию.
Этот тип индекса строится на основе сбалансированного дерева, где поиск выполняется за логарифмическое время. B-tree индексы полезны в следующих ситуациях:
- Для поиска по уникальным ключам или диапазонам.
- Для индексации строк, чисел и дат.
Пример создания B-tree индекса:
Hash индексы: используются для быстрого точного поиска по ключу (=). Эти индексы не поддерживают диапазонные операции, такие как < или >, и поэтому применимы только для точного поиска.
Hash индексы могут быть более эффективны, чем B-tree для операций с хешированием, но они используются реже, так как поддержка функциональности B-tree шире.
GIN (Generalized Inverted Index): используется для случаев, когда один столбец содержит несколько значений, например, массивы, JSON, и при полнотекстовом поиске. GIN хранит инвертированный индекс, который ассоциирует значения с идентификаторами строк, что ускоряет поиск по множеству элементов внутри одного столбца.
Этот тип индекса используется для таких операций, как:
- Поиск элементов внутри массивов.
- Поиск ключей и значений в JSON-документах.
- Полнотекстовый поиск по строкам.
Пример создания GIN индекса:
Пример запроса с использованием GIN:
Здесь @> — это оператор для поиска элементов внутри массива.
GiST (Generalized Search Tree): предоставляют более гибкую структуру для индексирования сложных типов данных, таких как:
- Геометрические объекты (точки, линии, полигоны).
- Текстовые поисковые операции.
- Иерархические структуры и расстояния.
GiST индексы поддерживают операции, связанные с расстояниями, перекрытием геометрических фигур и многими другими, что делает их идеальными для геопространственных данных.
Пример создания GiST индекса:
Пример запроса с использованием GiST:
Здесь && — оператор для поиска пересечений между геометрическими фигурами.
BRIN (Block Range INdex): предназначены для индексации больших таблиц, в которых данные хранятся последовательно. Этот тип индексов требует меньше места, чем B-tree, но он менее точен. BRIN индексы не хранят точные значения, а вместо этого сохраняют диапазоны блоков данных.
Они особенно полезны для колонок, где значения меняются в определенном порядке, например, временные метки или идентификаторы. Примером может быть таблица с логами, где записи хранятся по возрастанию времени.
Пример создания BRIN индекса:
Выбор индекса
- Если нужно быстро искать значения по ключу или диапазону — используйте B-tree.
- Для поиска точных значений с использованием хеширования — Hash.
- Для работы с множеством значений внутри одного столбца или полнотекстового поиска — GIN.
- Для работы с геометрическими данными или сложными типами — GiST.
- Для больших последовательных данных (например, временных меток) — BRIN.