|
5 | 5 | - [Паттерны баз данных](#паттерны-баз-данных) |
6 | 6 | - [Движки баз данных](#движки-баз-данных) |
7 | 7 | - [Проблема n + 1](#проблема-n-1) |
| 8 | +- [Оптимизация SQL-запросов](#оптимизация-sql-запросов) |
8 | 9 |
|
9 | 10 | <!-- |
10 | 11 | - [Резидентные базы данных](#резидентные-базы-данных) |
@@ -144,22 +145,100 @@ START TRANSACTION; |
144 | 145 | ## Индекс базы данных |
145 | 146 | - [Об индексе базы данных](#об-индексе-базы-данных) |
146 | 147 | - [Проблема дублирования данных](#проблема-дублирования-данных) |
| 148 | +- [Основные типы индексов](#основные-типы-индексов) |
147 | 149 |
|
148 | 150 | ### Об индексе базы данных |
149 | 151 |
|
150 | 152 | **Индекс базы данных** (англ. `database index`) — это структура данных, ускоряющая операции поиска (англ. `speed up querying`) в заданной таблице (или коллекции) базы данных за счёт хранения дополнительной информации в базе (говоря простыми словами, тех же данных таблицы, но в другом виде, в упорядоченном). |
151 | 153 |
|
152 | | -По умолчанию записи в таблице (коллекции) могут храниться произвольно (неупорядоченно). И если таблица довольно большая, то последовательный просмотр всех записей может занимать довольно продолжительное время. Индексы приводят данные в такой вид (упорядочивают их), чтобы это ускорило поиск. Например, структура индекста может быть представлена *сбалансированным деревом поиска*, и тогда скорость поиска будет логарифмичной `O(log n)` вместо линейной `O(n)`. |
| 154 | +*Индекс* — это дополнительная структура данных, например, в виде дерева, которая позволяет быстро найти нужные строки, не перебирая всю таблицу (англ. `Full Table Scan`). Индексы хранят упорядоченные или быстро доступные ссылки на строки таблицы. Это похоже на оглавление в книге, которое позволяет быстро найти нужную страницу. |
| 155 | + |
| 156 | + |
| 157 | +По умолчанию записи в таблице (коллекции) могут храниться произвольно (неупорядоченно). И если таблица довольно большая, то последовательный просмотр всех записей может занимать довольно продолжительное время. Индексы приводят данные в такой вид (упорядочивают их), чтобы это ускорило поиск. Например, структура индекса может быть представлена *сбалансированным деревом поиска*, и тогда скорость поиска будет логарифмичной `O(log n)` вместо линейной `O(n)`. |
153 | 158 |
|
154 | 159 | Индекс формируется из значений одного или нескольких столбцов таблицы (полей документов коллекции) и указателя на соответствующие строки таблицы (документы коллекции). Также иногда индексы могут создаваться из выражений. |
155 | 160 |
|
156 | | -Таким образом, если вы создаёте индекс по какому-то столбцу таблицы, скажем, по имени пользователя, вы можете быстрее найти (получить) данные пользователей из таблицы по заданному имени (выигрываете в скорости, во времени), но нужно учитывать, что индекс подразумевает дублирование некоторых данных (проигрываете в памяти). |
| 161 | +### Основные типы индексов: |
| 162 | +#### Бинарное дерево (B-дерево, B-tree) |
| 163 | + |
| 164 | +Наиболее распространённый тип индекса (чаще всего используется по умолчанию). Организован в виде сбалансированного дерева (англ. `AVL-Tree`). |
| 165 | +Когда использовать: |
| 166 | + • Поиск точных значений (например, `WHERE id = 10`) |
| 167 | + • Поиск диапазонов (`WHERE date BETWEEN x AND y`) |
| 168 | + • Сортировка (`ORDER BY`) |
| 169 | + • `JOIN` по индексированным полям |
| 170 | +Недостатки: |
| 171 | + • Менее эффективен при поиске текста по шаблону (например, с `LIKE '%search%'`) |
| 172 | + • Ненужное создание множества таких индексов может снизить производительность при вставке и обновлении записей |
| 173 | + |
| 174 | +#### Хеш-индексы (Hash Index) |
| 175 | +Используют хеш-функции для быстрого поиска по точному соответствию ключа. |
| 176 | + |
| 177 | +Когда использовать: |
| 178 | + • Очень быстрый поиск по точному совпадению (например, `WHERE username = 'user123'`) |
| 179 | +Недостатки: |
| 180 | + • Не поддерживают поиск по диапазону (`BETWEEN`, `<`, `>`) или сортировку |
| 181 | + • Не подходят для поиска частичных совпадений |
| 182 | + • Чаще используются в специализированных БД (например, in-memory хранилищах) |
| 183 | + |
| 184 | +#### Полнотекстовый индекс (Full-Text Index) |
| 185 | + |
| 186 | +Используются для поиска слов или фраз в тексте. |
| 187 | +Когда использовать: |
| 188 | + • Полнотекстовый поиск по большим текстовым полям (`LIKE` недостаточно эффективен) |
| 189 | +Примеры СУБД: |
| 190 | + • MySQL (MATCH AGAINST) |
| 191 | + • PostgreSQL (GIN, GIN индексы) |
| 192 | + |
| 193 | +#### Многоколоночные (композитные) индексы (Composite Index) |
| 194 | + |
| 195 | +Состоят из нескольких полей таблицы. |
| 196 | + |
| 197 | +Когда использовать: |
| 198 | + • Запросы, включающие несколько полей одновременно (WHERE name = X AND date = Y) |
| 199 | + • Частые сложные условия с множеством критериев |
| 200 | +Важно: |
| 201 | + • Порядок столбцов в индексе очень важен. Первым указывается поле, по которому чаще всего происходит поиск или фильтрация. |
| 202 | + |
| 203 | +#### Уникальный индекс (Unique Index) |
| 204 | +Не допускает повторяющихся значений. |
157 | 205 |
|
158 | | -### Проблема дублирования данных |
| 206 | +Когда использовать: |
| 207 | + • Поля, значения которых должны быть уникальными (например, `email`, `phone`, `username`) |
159 | 208 |
|
160 | | -Важно быть аккуратными с индексами, потому что за любым изменением в таблице (коллекции) должно последовать обновление индекса. Когда данных очень много, это может повлечь за собой очень трудоёмкие вычисления и большую нагрузку на сервер соответственно. |
| 209 | +#### Частичные индексы (Partial Index) |
161 | 210 |
|
162 | | -Более того, индексы занимают дополнительное место, поэтому не стоит их создавать (хранить) без необходимости. |
| 211 | +Индексы, применяемые только к части строк таблицы (по условию). |
| 212 | +Когда использовать: |
| 213 | + • Если часто выбирается лишь небольшая часть данных (например, только активные пользователи) |
| 214 | + |
| 215 | +#### Многомерные индексы (R-Tree, GIN, GiST) |
| 216 | + |
| 217 | +Используются для специфических типов данных (пространственные данные, JSON и пр.). |
| 218 | +Когда использовать: |
| 219 | + • Геоданные (например, геолокации, поиск по карте) |
| 220 | + • JSON-данные с поиском по внутренним полям |
| 221 | + |
| 222 | +### Преимущества и недостатки индексов |
| 223 | + |
| 224 | +Количество индексов прямо влияет на производительность |
| 225 | +* Много индексов: |
| 226 | +➕ Ускоряет многие запросы на чтение |
| 227 | +➖ Значительно замедляет операции записи (`INSERT, UPDATE, DELETE`), увеличивает размер базы данных, повышает нагрузку на сервер. |
| 228 | +* Недостаточно индексов: |
| 229 | +➕ Быстрая запись данных |
| 230 | +➖ Медленные запросы на чтение, полное сканирование таблиц, неоптимальная нагрузка на сервер. |
| 231 | + |
| 232 | +Таблица с 5 индексами при добавлении новой строки база данных должна обновить все 5 индексов, что занимает больше времени, чем без индексов или с одним индексом. |
| 233 | + |
| 234 | +Создавайте индексы только на те поля, которые часто используются в запросах. |
| 235 | +Избегайте индексов на полях с низкой селективностью (например, пол (мужчина/женщина) — плохой кандидат для индекса, так как пользы почти не принесёт). |
| 236 | + |
| 237 | +Правильное использование индексов — это баланс между скоростью чтения, скоростью вставки и обновления данных, а также объёмом используемого места. |
| 238 | + |
| 239 | +Индексы ускоряют чтение, но замедляют операции записи (INSERT, UPDATE, DELETE). |
| 240 | + • Используйте индексы осознанно: больше индексов ≠ всегда лучше. |
| 241 | + • Регулярно проверяйте производительность запросов (с помощью EXPLAIN) и оптимизируйте набор индексов. |
163 | 242 |
|
164 | 243 | ## Курсор |
165 | 244 | - [О курсоре](#о-курсоре) |
@@ -1865,3 +1944,67 @@ GET /posts/_search |
1865 | 1944 | } |
1866 | 1945 | ``` |
1867 | 1946 | ## Mongoose, проблема n + 1 и populate |
| 1947 | + |
| 1948 | + |
| 1949 | +# Оптимизация SQL-запросов |
| 1950 | + |
| 1951 | +## Анализ производительности запросов |
| 1952 | + |
| 1953 | +Команда `EXPLAIN` — основной инструмент анализа производительности запросов. |
| 1954 | +```sql |
| 1955 | +EXPLAIN SELECT * FROM users WHERE email = '[email protected]'; |
| 1956 | +``` |
| 1957 | +Она позволяет смотреть |
| 1958 | +* типы доступа к данным (Index Scan, Full table scan и тд) |
| 1959 | +* используемые индексы и их эффективность |
| 1960 | +* количество просматриваемых строк |
| 1961 | + |
| 1962 | +## Индексы |
| 1963 | +**Индексы** – *важнейший инструмент ускорения поиска запроса* |
| 1964 | +Создавай индекс для полей, которые используются в |
| 1965 | +* `JOIN` |
| 1966 | +* `WHERE` |
| 1967 | +* `ORDER BY` |
| 1968 | +* `GROUP BY` |
| 1969 | + |
| 1970 | +Учитывайте **селективность** (индексируй поля с высокой уникальностью). |
| 1971 | + |
| 1972 | +Пример создания индекса |
| 1973 | +```sql |
| 1974 | +CREATE INDEX idx_users_email ON users(email); |
| 1975 | +``` |
| 1976 | + |
| 1977 | +## Выбирайте только нужные поля таблицы и не используй `SELECT *` |
| 1978 | +```sql |
| 1979 | +# плохо |
| 1980 | +SELECT * |
| 1981 | +# хорошо |
| 1982 | +SELECT id, username FROM users; # хорошо |
| 1983 | +``` |
| 1984 | + |
| 1985 | +## Избегайте лишних JOIN и подзапросов |
| 1986 | +Используйте `JOIN` вместо подзапросов, если это возможно |
| 1987 | +```sql |
| 1988 | +# плохо - подзапрос |
| 1989 | +SELECT id, (SELECT id FROM orders WHERE orders.user_id = users.id) FROM users; |
| 1990 | +# хорошо - JOIN |
| 1991 | +SELECT users.id, orders.id FROM users JOIN orders ON orders.user_id = users.id; |
| 1992 | +``` |
| 1993 | + |
| 1994 | +## Используйте пагинацию, когда это возможно |
| 1995 | +Задайте `LIMIT` и `OFFSET` |
| 1996 | +```sql |
| 1997 | +SELECT id, username FROM users LIMIT 50 OFFSET 0; |
| 1998 | +``` |
| 1999 | + |
| 2000 | +## Грамотно используйте условия WHERE и агрегацию |
| 2001 | + |
| 2002 | +## Регулярно чистите базу, выполняйте оптимизацию таблиц и перестройку индексов |
| 2003 | +```sql |
| 2004 | +OPTIMIZE TABLE your_table |
| 2005 | +``` |
| 2006 | +## Следите за производительностью запросов |
| 2007 | +Например, в MySQL можно сделать так |
| 2008 | +```sql |
| 2009 | +SET GLOBAL slow_query_log = 'ON'; |
| 2010 | +``` |
0 commit comments