Добавление заметок про индексы и оптимизации SQL
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Struchkov Mark 2024-10-25 20:04:39 +03:00
parent e30be72fab
commit eacf800157
No known key found for this signature in database
GPG Key ID: A3F0AC3F0FA52F3C
54 changed files with 1566 additions and 203 deletions

View File

@ -64,7 +64,7 @@ UUID версии 4 (V4) — это случайный идентификато
**Недостатки:**
- **Не сортируемый**: UUID V4 нельзя отсортировать по времени или другим критериям, так как он полностью основан на случайных данных.
- **Замедленная вставка в БД**: В больших базах данных, по мере увеличения количества записей, время вставки новых записей с UUID V4 может расти. Это связано с тем, что случайные значения распределяются неравномерно, что может вызывать фрагментацию [[../../../_inbox/Индекс в БД|индексов]], особенно при использовании кластеризованных индексов.
- **Замедленная вставка в БД**: В больших базах данных, по мере увеличения количества записей, время вставки новых записей с UUID V4 может расти. Это связано с тем, что случайные значения распределяются неравномерно, что может вызывать фрагментацию [[database/Индекс в БД|индексов]], особенно при использовании кластеризованных индексов.
- **Не содержит полезной информации**: В отличие от UUID версий 1 и 3, UUID V4 не хранит никаких дополнительных данных (например, метку времени или привязку к конкретному объекту).
## UUID V5
![](../meta/files/images/Pasted%20image%2020231112134012.png)

View File

@ -26,7 +26,7 @@ GZIP (GNU ZIP) — это формат сжатия данных и програ
**Реализации:**
- [[../../../../_inbox/Реализация GZIP в Java|Реализация GZIP в Java]]
- [[../../../../_inbox/GZIP сжатие в Nginx|GZIP сжатие в Nginx]]
- [[../devops/nginx/GZIP сжатие в Nginx|GZIP сжатие в Nginx]]
***
## Мета информация
@ -40,7 +40,7 @@ GZIP (GNU ZIP) — это формат сжатия данных и програ
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
<!-- SerializedQuery: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
- [[GZIP сжатие в Nginx]]
- [[Реализация GZIP в Java]]
- [[GZIP сжатие в Nginx]]
<!-- SerializedQuery END -->

View File

@ -11,11 +11,9 @@ linked: []
---
При реализации [[highload/Кэширование на стороне браузера|кэширования на стороне браузера]] важно иметь механизм [[highload/Инвалидация кэша|инвалидации кэша]]. Иначе пользователи могут продолжить видеть неактуальные JS-скрипты и CSS-стили, что приведет к проблемам.
Самый простой способ побороть эту проблему, это использовать fingerprint файла. То есть, когда файл меняется, вы меняете его название. Делается это обычно добавлением какого-нибудь префикса/суфикса к названию файла.
Fingerprint — это метод, при котором при каждом изменении файла его название изменяется. Обычно это делается путем добавления префикса или суффикса, сгенерированного на основе хэша файла. Например, для файла стилей `style.css` можно вычислить его [[../cryptography/MD5|MD5]]-хэш и добавить его к имени файла. В итоге получится файл с именем `style.e626dd36e0085927f334adbe3eb38e7a.css`.
Например у нас есть файл стилей `style.css`, мы можем посчитать для него [[../cryptography/MD5|MD5]] хеш и добавить его в название. Тогда у нас получится следующее название: `style.e626dd36e0085927f334adbe3eb38e7a.css`.
При любом изменении файла [[../cryptography/MD5|MD5]] хеш должен пересчитываться. Таким образом при изменении файла у него будет другое название, и браузер будет вынужден скачать его в любом случае.
Каждый раз, когда файл изменяется, хэш пересчитывается, и файл получает новое имя. Это заставляет браузер скачать актуальную версию файла, игнорируя старую кэшированную копию.
***
## Мета информация
**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]

View File

@ -1,70 +0,0 @@
---
aliases:
tags:
- maturity/🌱
date:
- - 2024-04-07
zero-link:
- "[[00 Nginx]]"
parents:
- "[[../Кэширование|Кэширование]]"
linked:
- "[[Кэширование статики в Nginx]]"
---
Если какие-то запросы не часто меняются, то можно закэшировать их на стороне сервера. Тогда Nginx один раз получит результат запроса от вашего приложения, а дальше будет отдавать их другим клиентам.
Перед настройками, нам нужно создать директорию, в которой будут хранится данные кэша:
```shell
sudo mkdir -p /var/nginx/cache
```
Чтобы включить кэширование, нужно прописать несколько директив в основной конфигурации `nginx.conf`.
```nginx
http {
proxy_cache_path /var/nginx/cache levels=1:2 keys_zone=nginxcash:60m max_size=256m inactive=24h;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_methods GET HEAD;
proxy_cache_min_uses 2;
}
```
`proxy_cache_path` указывает путь в файловой системе.
Не кэшируйте HTTP-ответы при первом обращении. Используйте `proxy_cache_min_uses 2`, чтобы кэшировать только те элементы, к которым обращались более одного раза. Таким образом, вы уменьшите нагрузку прокси-кэша на запись и предотвратите заполнение кэша содержимым, к которому редко обращаются.
Ключ кэширования Nginx по умолчанию не очень хорошо работает с сайтами с несколькими поддоменами. Вы можете настроить ключ кэширования, задав proxy_cache_key. В своей конфигурации я использую вот такой ключ: `proxy_cache_key $scheme$host$uri$is_args$args;`
## Переносим кэш Nginx в RAM
Можно значительно ускорить кэш, если смонтировать его не в файловую систему а в RAM.
Для этого также создаем папку для кэша, можно использовать ту же, но ее нужно очистить от папок. Далее монтируем созданный каталог в RAM с помощью команды [tmpfs](https://wiki.archlinux.org/index.php/Tmpfs), выделяя 256 мегабайт под кэш:
```shell
sudo mount -t tmpfs -o size=256M tmpfs /var/nginx/cache
```
Если вам понадобиться отключить RAM-кэш, просто выполните команду:
```shell
sudo umount /var/nginx/cache
```
Чтобы автоматически пересоздать каталог к'ша в RAM после перезагрузки сервера, нам нужно обновить файл `/etc/fstab`. Добавьте в него следующую строку:
```txt
tmpfs /var/nginx/cache tmpfs defaults,size=256M 0 0
```
***
## Мета информация
**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]]
**Родитель**:: [[../Кэширование|Кэширование]]
**Источник**::
**Автор**::
**Создана**:: [[2024-04-07]]
### Дополнительные материалы
- [Оптимизация NGINX](https://struchkov.dev/blog/ru/nginx-optimization/)
- [Nginx cache: всё новое — хорошо забытое старое / Хабр](https://habr.com/ru/post/428127/)
- [[../../../../../_inbox/Кэширование статики в Nginx|Кэширование статики в Nginx]]
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -10,6 +10,8 @@ parents:
- "[[../Кэширование|Кэширование]]"
linked:
---
Статический контент — это элементы веб-сайта, которые остаются неизменными на протяжении долгого времени на всех страницах. К такому контенту относятся файлы изображений, CSS и JavaScript. Поскольку эти файлы редко изменяются, их можно сохранять в кэше браузера пользователя. Это позволяет браузеру загружать локальные копии файлов, а не запрашивать их каждый раз с сервера, что ускоряет работу сайта.
Обычно кэшируются только GET запросы, так как они должны быть [[../Идемпотентность|идемпотентны]].
Заголовки для кэширования:
@ -23,24 +25,21 @@ linked:
- max-age - Сколько нужно хранить файл в памяти
- LocalStorage. Можно через JS складывать данные.
Статический контент - это содержимое сайта, которое остается неизменным продолжительное время на всех страницах. Например, это такие файлы, как картинки, CSS и JS файлы.
Так как эти файлы редко изменяются, то можно сохранять их в кэше браузера пользователя. Вместо того, чтобы обращаться к серверу каждый раз, браузер будет использовать свою локальную копию этих файлов.
![](../../../meta/files/images/Pasted%20image%2020240619083856.png)
Инвалидация:
- Самый простой вариант указывать версию в GET параметрах.
- Для статики можно использовать [[../Fingerprint]]
- Для статики можно использовать [[../Fingerprint|Fingerprint]]
***
## Мета информация
**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]]
**Родитель**::
**Родитель**:: [[../Кэширование|Кэширование]]
**Источник**::
**Автор**::
**Создана**:: [[2024-06-17]]
### Дополнительные материалы
- [[Кэширование статики в Nginx]]
- [[../../devops/nginx/Кэширование статики в Nginx]]
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -29,7 +29,7 @@ linked:
Уровни кэширования:
- [Кэширование на стороне браузера](highload/Кэширование%20на%20стороне%20браузера.md)
- [Кэширование на стороне Nginx](highload/Кэширование%20на%20стороне%20Nginx.md)
- [Кэширование на стороне Nginx](../devops/nginx/Кэширование%20на%20стороне%20Nginx.md)
- [Content Delivery Network](highload/Content%20Delivery%20Network.md)
- [Кэширование в приложении](Кэширование%20в%20приложении.md)
@ -58,15 +58,14 @@ linked:
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
<!-- SerializedQuery: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
- [[Кэширование статики в Nginx]]
- [[CacheMissRate]]
- [[Content Delivery Network]]
- [[Инвалидация кэша]]
- [[Ключ кэширования]]
- [[Кэширование на стороне Nginx]]
- [[Кэширование на стороне браузера]]
- [[Оценка эффективности кэша]]
- [[Перестройка кэша]]
- [[Старт с холодным кэшем]]
- [[Кэширование в приложении]]
- [[Кэширование на стороне Nginx]]
<!-- SerializedQuery END -->

View File

@ -27,7 +27,7 @@ linked:
- **Изоляция ошибок.** Если происходит ошибка в одном потоке, она может повлиять на множество запросов, поскольку один поток обслуживает сразу несколько клиентов. В таких случаях важно предусмотреть механизмы обработки ошибок и защиты от сбоев.
**Кто использует этот подход**
- [[../../../../wiki/zero/00 Nginx|Nginx]]. Один из самых известных примеров событийно-ориентированного сервера, использующий асинхронный подход. Nginx эффективно обрабатывает множество клиентских запросов с минимальными затратами ресурсов.
- [[../../meta/zero/00 Nginx|Nginx]]. Один из самых известных примеров событийно-ориентированного сервера, использующий асинхронный подход. Nginx эффективно обрабатывает множество клиентских запросов с минимальными затратами ресурсов.
- **Node.js.** Однопоточная архитектура с использованием событийной петли, которая позволяет одному потоку обрабатывать множество запросов одновременно. Node.js широко применяется для построения масштабируемых серверов и микросервисов.
- Vert.x и [[../../meta/zero/00 Quarkus|Quarkus]]. Эти фреймворки используют реактивные подходы для обработки запросов, обеспечивая высокую производительность и асинхронную обработку данных в [[../../../../wiki/zero/Микросервисная архитектура|микросервисной архитектуре]].
- Netty. Асинхронный сетевой фреймворк, который широко используется для создания высокопроизводительных сетевых приложений на Java, таких как серверы и клиентские приложения.

View File

@ -35,7 +35,7 @@ linked:
**Современные альтернативы**
С ростом масштабов приложений, особенно в веб-разработке, стали популярны асинхронные и реактивные подходы, где один поток может обслуживать множество клиентов, не создавая новый поток для каждого запроса. Такие подходы позволяют лучше использовать ресурсы системы:
- **Асинхронные модели.** Серверы, такие как [[../../../../wiki/zero/00 Nginx|Nginx]], используют [[../../../../_inbox/Событийно-ориентированное программирование|событийно-ориентированную архитектуру]], где запросы обрабатываются без необходимости создавать новый поток на каждый запрос. Это снижает потребление памяти и улучшает масштабируемость.
- **Асинхронные модели.** Серверы, такие как [[../../meta/zero/00 Nginx|Nginx]], используют [[../../../../_inbox/Событийно-ориентированное программирование|событийно-ориентированную архитектуру]], где запросы обрабатываются без необходимости создавать новый поток на каждый запрос. Это снижает потребление памяти и улучшает масштабируемость.
- [[../../../../knowledge/dev/Реактивное программирование|Реактивное программирование]]. В таких фреймворках, как [[../../meta/zero/00 Quarkus|Quarkus]], Vert.x или [[../../meta/zero/00 SpringBoot|Spring]] WebFlux, запросы обрабатываются асинхронно с использованием реактивных потоков, что позволяет эффективно распределять ресурсы даже при высокой нагрузке.
***

View File

@ -14,7 +14,7 @@ linked:
![](Pasted%20image%2020240523133746.png)
- [Фронтенд](Фронтенд.md). предназначен для быстрой обработки легких данных, как правило, статики. Эти запросы обрабатываются тут и не проходят на массивный, тяжелый бэкенд. Для фронтенда используются такие легковесные сервера, как [nginx](00%20Nginx.md). В разработке подобных серверов огромное внимание уделяется тому, какое количество ресурсов тратится на обработку одного запроса.
- [Фронтенд](Фронтенд.md). предназначен для быстрой обработки легких данных, как правило, статики. Эти запросы обрабатываются тут и не проходят на массивный, тяжелый бэкенд. Для фронтенда используются такие легковесные сервера, как [nginx](../../meta/zero/00%20Nginx.md). В разработке подобных серверов огромное внимание уделяется тому, какое количество ресурсов тратится на обработку одного запроса.
- [Бэкенд](Бэкенд.md), как правило, это тяжелые приложения, в которых происходят вычисления, зашита бизнес-логика, и обрабатывать статические запросы бэкендом попросту неэффективно.
- Следующий слой это хранение данных, в простейшем варианте [база данных](../../meta/zero/00%20Базы%20Данных.md).
***

View File

@ -0,0 +1,37 @@
---
aliases:
- OLAP
tags:
- maturity/🌱
date: 2024-03-31
---
OLAP (Online Analytical Processing) — это тип нагрузки, который ориентирован на выполнение сложных аналитических запросов, охватывающих большие объемы данных. OLAP используется для построения отчетов, аналитики и поддержки принятия решений, где важно работать с историческими данными и выполнять сложные агрегации.
**Особенности:**
- Операции SELECT выполняются значительно чаще, чем операции изменения данных.
- Запросы часто содержат операции агрегации (например, SUM, AVG) и группировки (GROUP BY).
- Запросы SELECT охватывают большие выборки данных и могут включать сложные агрегации и группировки.
Примеры задач:
- Поиск зависимостей по товарам, которые пользователи покупают вместе.
- Получение информации о продажах за последние 3 года.
- Построение аналитики по шаблонам платежей по группам пользователей.
Причины выделить OLAP нагрузку:
- Разный характер нагрузки, требующий долгосрочного хранения и анализа данных.
- Специфические стратегии [[Индекс в БД|индексирования]] для оптимизации аналитических запросов.
- Работа с большими объемами данных и их обработка в рамках одного запроса.
- Поддержка исторических данных для анализа трендов и построения отчетов.
Это не то же самое, что создание отдельной реплики для отчетности, так как это не решает проблему разных индексов. Однако на логической репликации это возможно.
***
## Мета информация
**Область**:: [[../../meta/zero/00 Базы Данных|00 Базы Данных]]
**Родитель**::
**Источник**::
**Автор**::
**Создана**:: [[2024-03-31]]
### Дополнительные материалы
- [[Online Transaction Processing]]
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,35 @@
---
aliases:
- OLTP
tags:
- maturity/🌱
date: 2024-03-31
---
OLTP (Online Transaction Processing) — это тип нагрузки, который характеризуется выполнением большого количества коротких транзакций, таких как операции вставки, обновления и удаления. OLTP-системы обычно используются для поддержки оперативной деятельности, где важна быстрая обработка данных.
**Особенности:**
- Множество маленьких и быстрых [[Транзакция БД|транзакций]].
- Частое выполнение операций `INSERT`, `UPDATE`, `DELETE`.
- Подавляющее большинство операций затрагивает только одну строку.
- Запросы должны выполняться максимально быстро.
Примеры задач:
- Продажа товаров пользователям.
- Прием платежей за сотовую связь.
## Лучшие практики для оптимизации производительности
- **Использование индексов**: правильно настроенные [[Индекс в БД|индексы]] позволяют быстрее выполнять операции и уменьшить количество операций чтения.
- [[../../../../_inbox/Шардирование БД|Шардинг]] (разделение таблиц): разделение таблиц на части снижает нагрузку и улучшает производительность.
- **Избегание блокировок**: минимизация блокировок таблиц и строк особенно важна при большом количестве параллельных транзакций.
- Для OLTP-нагрузки не следует использовать параллельное выполнение запросов, так как это забирает ядро процессора у другого запроса, что может привести к задержкам в обработке транзакций и снижению общей производительности системы. В контексте OLTP важнее минимизировать время выполнения каждого отдельного запроса, а не распределять его между несколькими ядрами. ==Каждый запрос должен выполняться на одном ядре как можно быстрее.==
***
## Мета информация
**Область**:: [[../../meta/zero/00 Базы Данных|00 Базы Данных]]
**Родитель**::
**Источник**::
**Автор**::
**Создана**:: [[2024-03-31]]
### Дополнительные материалы
- [[Online Analytical Processing]]
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,34 @@
---
aliases:
- B-tree индекс
- B-tree
tags:
- maturity/🌱
date: 2024-10-23
---
**Особенности:**
- Основан на работе [[../../fundamental/structure/B-tree|B-tree]] дерева.
- Подходит для операций сравнения (`<`, `>`, `BETWEEN`), равенства (`=`) и сортировки.
- Хорошо оптимизирован для большинства операций чтения и поиска.
- Покрывает до 90% задач по индексации в типичных приложениях.
- Не рекомендуется для данных с высокой степенью повторения, так как эффективность индекса в таких случаях может снижаться.
Пример создания:
```sql
CREATE INDEX idx_name ON table_name (column_name);
```
Индекс легко создать, ориентируясь на [[Таблица статистик pg_stats|pg_stats]].
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[Индекс в PostgreSQL|Индекс в PostgreSQL]]
**Источник**::
**Создана**:: [[2024-10-23]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,26 @@
---
aliases:
- BRIN индекс
tags:
- maturity/🌱
date: 2024-10-24
---
BRIN индекс предназначен для больших таблиц с упорядоченными данными, таких как временные ряды. Это компактный и эффективный индекс для работы с диапазонными запросами.
Пример создания:
```sql
CREATE INDEX idx_name ON table_name USING brin (column_name);
```
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[Индекс в PostgreSQL|Индекс в PostgreSQL]]
**Источник**::
**Создана**:: [[2024-10-24]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,34 @@
---
aliases:
- GIN индекс
tags:
- maturity/🌱
date: 2024-10-24
---
**Особенности GIN индекса в PostgreSQL:**
- Подходит для ускорения полнотекстового поиска и работы с полями типа `tsvector` или `jsonb`.
- Полезен для поиска по документам и массивам, позволяя быстро находить совпадения по множественным значениям.
- Может ухудшить производительность операций записи, поэтому важно учитывать это при выборе индексации.
Пример создания:
```sql
CREATE INDEX idx_name ON table_name USING gin (column_name);
```
**Оптимизация работы с GIN индексами:**
- При работе с `jsonb` полями доступны два типа операций индексации:
- `jsonb_ops`: Индексирует все ключи и значения, создавая объемный индекс, который подходит для универсального поиска.
- `jsonb_path_ops`: Индексирует пути в JSON, создавая более компактный индекс, подходящий для задач, где необходимо искать по конкретным путям.
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[Индекс в PostgreSQL|Индекс в PostgreSQL]]
**Источник**::
**Создана**:: [[2024-10-24]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,33 @@
---
aliases:
- Gist индекс
tags:
- maturity/🌱
date: 2024-10-23
---
**Особенности GiST индекса в PostgreSQL:**
- Используется для индексации сложных данных, таких как геометрия и гео-данные.
- Подходит для задач, связанных с пространственными запросами, например, для поиска ближайшей гео-точки.
- Гибкий механизм, позволяющий расширять функциональность индексации за счет различных расширений, таких как `pg_trgm` и `btree_gist`.
**Пример создания**
```sql
CREATE INDEX idx_name ON table_name USING gist (column_name);
```
**Поддерживаемые расширения для GiST индекса:**
- `pg_trgm`: Поддерживает операции `LIKE`, `ILIKE`, `~`, `~*` (регулярные выражения), что делает его полезным для быстрого полнотекстового поиска.
- `btree_gist`: Добавляет поддержку B-tree в GiST и позволяет делать сложные ограничения (constraints) с интервалами, например, контроль пересечения времени для создания расписания.
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[Индекс в PostgreSQL]]
**Источник**::
**Создана**:: [[2024-10-23]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,30 @@
---
aliases:
- Hash индекс
tags:
- maturity/🌱
date: 2024-10-23
---
**Особенности:**
- Подходит для операций равенства (`=`), но **не поддерживает сортировку** и операции диапазона (`<`, `>`, `BETWEEN`).
- Занимает меньше места на диске по сравнению с [[B-tree индекс в PostgreSQL|B-tree]].
**Пример создания:**
```sql
CREATE INDEX idx_name ON table_name USING hash (column_name);
```
Хэш-индексы могут быть полезны для ускорения поиска по колонкам с бинарными значениями или другими типами данных, где часто используются точные совпадения.
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[Индекс в PostgreSQL]]
**Источник**::
**Создана**:: [[2024-10-23]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,24 @@
---
aliases:
- SP-GiST индекс
tags:
- maturity/🌱
date: 2024-10-24
---
**Особенности SP-GiST индекса в PostgreSQL:**
- Подходит для специфических структур данных, таких как разреженные данные, вложенные множества или данные с неравномерным распределением.
- Обычно не используется в приложениях типа [[../Online Transaction Processing|OLTP]], так как его преимущества не очевидны для типичных транзакционных нагрузок.
- Может быть полезен в научных или аналитических приложениях, где требуется работа с разреженными или геометрическими данными.
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[Индекс в PostgreSQL]]
**Источник**::
**Создана**:: [[2024-10-24]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,54 @@
---
aliases:
- pageinspect
tags:
- maturity/🌱
date: 2024-10-21
---
Установка расширения
```sql
create extension pageinspect
```
## Анализ индексов
Расширение pageinspect позволяет изучить структуру индекса (размер страницы, количество страниц и так далее).
![](../../../meta/files/images/Pasted%20image%2020240610084449.png)
Проверить какие индексы существуют для таблицы:
```sql
select * from pg_indexes where tablename='table_name';
```
Посмотреть сколько раз индекс использовался и когда был последний вызов.
```sql
select * from pg_stat_user_indexes
```
Посмотреть размер индекса
```sql
select pg_size_pretty(pg_indexes_size('orders'))
```
Можно получить мета информацию о дереве индекса:
```sql
select * from bt_metap('users_pkey');
```
Можно получить мета информацию о конкретном узле:
```sql
select * from bt_page_stats('users_pkey', 3);
```
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[Оптимизация SQL запросов в PostgreSQL]]
**Источник**::
**Создана**:: [[2024-10-21]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,18 @@
---
aliases:
tags:
- maturity/🌱
date: 2024-06-17
---
Собирает всю статистику по запросам. Позволят получить агрегированный отчет по SQL запросу: минимальное время выполнения, максимальное, среднее. Но все запросы обезличенные - не содержат значения параметров.
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[Оптимизация SQL запросов в PostgreSQL|Оптимизация SQL запросов в PostgreSQL]]
**Источник**::
**Автор**::
**Создана**:: [[2024-06-17]]
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,15 @@
---
aliases:
tags:
- maturity/🌱
date: 2024-07-24
zero-link: []
parents:
linked:
---
- [GitHub - dataegret/pg-utils: Useful PostgreSQL utilities](https://github.com/dataegret/pg-utils)
- global_reports
- `top_tables.sql` - покажет размер таблиц и размер индексов на них. Нужно обратить внимания на таблицы, размер индексов которых приближается к размеру таблицы или больше его.
- `indexes_with_nulls.sql` - позволяет найти индексы, которые содержат множество null значений. Их можно пересоздать в виде [[Частичный индекс|частичных индексов]].
- `low_used_indexes.sql` - показывает индексы по которым мало чтения.

View File

@ -0,0 +1,49 @@
---
aliases: []
tags:
- maturity/🌱
date: 2024-03-31
---
[[../../../meta/zero/00 PostgreSQL|PostgreSQL]] поддерживает несколько типов [[../Индекс в БД|индексов]], каждый из которых предназначен для определённых задач. Выбор типа индекса зависит от структуры данных и характера запросов. В этом разделе приведены основные типы индексов, их особенности и случаи, когда их использование наиболее эффективно.
**Особенности:**
- Для **первичного ключа** индекс создается автоматически.
- Можно **отключить автоматическое обновление индекса** и настроить обновление вручную.
- **Распухание индексов** (bloat) — это проблема увеличения размера индексов со временем, требующая переиндексации.
- [[Создание индекса в PostgreSQL]]
- [[Частичный индекс]]
- [[Составной индекс в PostgreSQL]]
**Типы индексов:**
- [[B-tree индекс в PostgreSQL|B-tree индекс]]
- [[Hash индекс в PostgreSQL|Hash индекс]]
- [[Gist индекс в PostgreSQL|Gist индекс]]
- [[SP-GiST индекс в PostgreSQL|SP-GiST индекс]]
- [[GIN индекс в PostgreSQL|GIN индекс]]
- [[BRIN индекс в PostgreSQL|BRIN индекс]]
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[../Индекс в БД|Индекс в БД]]
**Источник**::
**Автор**::
**Создана**:: [[2024-03-31]]
### Дополнительные материалы
- [Доклад. Индексы в PostgreSQL. Как понять, что создавать](../../../source/lecture/Доклад.%20Индексы%20в%20PostgreSQL.%20Как%20понять,%20что%20создавать.md)
- [009. B-деревья. Система непересекающихся множеств - М. А. Бабенко - YouTube](https://www.youtube.com/watch?v=KFcpDTpoixo)
- [Индексы в PostgreSQL — 1 / Хабр](https://habr.com/ru/companies/postgrespro/articles/326096/)
- [Introduction of B+ Tree - GeeksforGeeks](https://www.geeksforgeeks.org/introduction-of-b-tree/)
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
<!-- SerializedQuery: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
- [[Создание индекса в PostgreSQL]]
- [[Частичный индекс]]
- [[Составной индекс в PostgreSQL]]
- [[B-tree индекс в PostgreSQL]]
- [[Hash индекс в PostgreSQL]]
- [[Gist индекс в PostgreSQL]]
- [[SP-GiST индекс в PostgreSQL]]
- [[GIN индекс в PostgreSQL]]
- [[BRIN индекс в PostgreSQL]]
<!-- SerializedQuery END -->

View File

@ -0,0 +1,59 @@
---
aliases:
tags:
- maturity/🌱
date: 2024-06-17
---
- [[../Оптимизация SQL запросов|Оптимизация SQL запросов]]
**Алгоритм оптимизации запросов:**
- **Проверка настроек**
- **Оборудование сервера БД**: убедитесь, что сервер имеет достаточную вычислительную мощность и оперативную память для обработки текущей нагрузки. Слабое оборудование может существенно снизить производительность.
- **Проблемы с сетью**: задержка в сети или потеря пакетов могут замедлять передачу данных между клиентом и сервером. Убедитесь в стабильности соединения.
- **Настройки базы данных**:
- Если у вас много соединений, используйте [[PgBouncer]], чтобы разгрузить управление соединениями.
- Проверьте, что `autovacuum` включен и настроен, чтобы избежать накопления "мусорных" строк, которые могут замедлить работу БД.
- Анализ и выбор [[../Плохой SQL запрос|проблемных запросов]]
- Оптимизировать все запросы подряд неэффективно. Начните с самых проблемных, чтобы добиться наибольшего улучшения.
- **Анализ проводите только на продуктовой БД**, так как тестовые среды могут не отражать реальную нагрузку.
- **Инструменты для анализа**:
- [pg_utils](pg_utils.md): утилиты для анализа производительности PostgreSQL.
- [[pg_stat_statements]]: расширение для сбора статистики выполнения запросов, помогает находить медленные запросы.
- [[Таблица статистик pg_stats|pg_stats]]: помогает определить, какие индексы стоит добавить или изменить.
- [[pageinspect]]: дает доступ к структуре страниц таблиц и индексов для глубокого анализа.
- **Оптимизация запросов**. Используйте [[Профилирование запросов в PostgreSQL|профилирование запросов в PostgreSQL]] для определения узких мест и точек, требующих оптимизации.
- **Изучение результатов оптимизации**. Проверьте улучшение производительности с помощью инструментов анализа, чтобы убедиться, что изменения действительно дают эффект.
- **Повторение анализа**. Оптимизация — это итеративный процесс. После улучшения одного запроса снова проанализируйте производительность системы и ищите новые узкие места.
**Конфигурационные параметры PostgreSQL**
- `work_mem`: увеличьте значение, если запросы требуют больших сортировок или операций с временными таблицами.
- `shared_buffers`: настройка этого параметра позволяет эффективно кэшировать данные в памяти и снижать количество обращений к диску.
- `maintenance_work_mem`: используйте для настройки памяти, выделяемой для операций обслуживания, таких как `VACUUM` и создание индексов.
![Почему JOIN работает медленно?](JOIN%20SQL.md#Почему%20JOIN%20работает%20медленно?)
![Проблемы производительности IN](IN%20SQL.md#Проблемы%20производительности%20IN)
PostgreSQL хранит статистику по выполнениям запросов в таблице `pg_stat_user_tables`. С её помощью можно оценить какие операции PostgreSQL выполняет чаще всего.
```sql
select relname, seq_scan, idx_scan, vacuum_count from pg_stat_user_tables
```
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[../Оптимизация SQL запросов|Оптимизация SQL запросов]]
**Источник**::
**Автор**::
**Создана**:: [[2024-06-17]]
### Дополнительные материалы
- [Производительность запросов в PostgreSQL / Илья Космодемьянский (PostgreSQL Consulting) - YouTube](https://www.youtube.com/watch?v=c-ySk8COI1c)
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
<!-- SerializedQuery: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
- [[Таблица статистик pg_stats]]
- [[Частичный индекс]]
- [[pageinspect]]
- [[Профилирование запросов в PostgreSQL]]
- [[pg_stat_statements]]
<!-- SerializedQuery END -->

View File

@ -0,0 +1,54 @@
---
aliases:
- explain
tags:
- maturity/🌱
date: 2024-06-10
---
Ключевое слово `EXPLAIN` перед SQL-запросом позволяет получить детальную информацию о том, как PostgreSQL **планирует** выполнить этот запрос "под капотом". Это полезно для диагностики производительности, поскольку помогает понять, какие шаги выполняет база данных и где могут быть узкие места.
Пример использования `EXPLAIN`
```sql
postgres=# EXPLAIN SELECT * FROM users WHERE id = 20;
QUERY PLAN
-------------------------------------------------------
Index Scan using users_pkey on users (cost=0.15..8.17 rows=1 width=72)
Index Cond: (id = 20)
(2 rows)
```
Вывод информации можно изменить. Например, чтобы получить результат в формате JSON:
```sql
EXPLAIN (FORMAT JSON) SELECT * FROM users WHERE id = 20;
```
> [!NOTE] Analyze
> `EXPLAIN` не выполняет сам запрос, поэтому результаты будут приблизительными. Для более точного анализа можно добавить ключевое слово `ANALYZE`, и тогда `EXPLAIN` также выполнит запрос.
## Стоимость выполнения запроса (cost)
PostgreSQL использует условные единицы для обозначения стоимости выполнения запроса — `cost`. Один `cost` примерно соответствует времени, затраченному на извлечение одного блока данных размером 8 килобайт при последовательном сканировании (Seq Scan).
Часто используются два значения `cost`:
- **Первое значение**: стоимость до начала получения первых результатов.
- **Второе значение**: полная стоимость выполнения запроса.
Если оценочное значение `rows` слишком низкое по сравнению с фактическим количеством строк, это может означать, что статистика таблицы устарела. В таком случае необходимо выполнить `ANALYZE` для обновления статистики и улучшения качества планирования запросов.
## Виды проходов по таблице и индексу
- **Seq Scan**: последовательный просмотр всей таблицы. Это наиболее медленный вариант и обычно нежелателен. Решение — добавить [[../Индекс в БД|индекс]], чтобы ускорить выборку данных.
- **Index Scan**: использование [[../Индекс в БД|индекса]] для просмотра таблицы.
- **Index Only Scan**: использование [[../Покрывающий индекс|покрывающего индекса]], когда все нужные данные находятся в индексе и не требуется дополнительного доступа к таблице.
- **Bitmap Heap Scan**: оптимизация с использованием битовых карт для поиска. Сначала строятся битовые карты с использованием нескольких индексов, затем они комбинируются.
- **Foreign Scan**: сканирование данных на удаленном сервере, используемое при [[Шардирование в PostgreSQL|шардировании]].
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[Оптимизация SQL запросов в PostgreSQL]]
**Источник**::
**Автор**::
**Создана**:: [[2024-01-29]]
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,34 @@
---
aliases:
tags:
- maturity/🌱
date: 2024-10-21
---
[PostgreSQL: Documentation: 16: CREATE INDEX](https://www.postgresql.org/docs/current/sql-createindex.html): рекомендуется ознакомиться с официальной документацией для более глубокого понимания команды `CREATE INDEX` и всех доступных опций.
**Что нужно для создания индекса?**
- **Соберите статистику нагрузки на БД**. **Работайте только с продуктовым окружением**: тестовые окружения не всегда отражают реальность.
- Используйте [[pg_stat_statements|pg_stat_statements]] для анализа запросов.
- Анализируйте [[Таблица статистик pg_stats|pg_stats]]: важно понимать, как планировщик БД строит план выполнения запроса.
- Инструмент pgBadge можно применять с осторожностью, так как он собирает данные из логов, в которые попадают не все запросы.
- **Примеры запросов с параметрами**: сохраняйте примеры для проверки оптимизаций.
- **Сбор дополнительной статистики**: при необходимости вручную собирайте более полные данные, так как по умолчанию PostgreSQL использует для анализа только 30k строк, что может давать неточную картину.
- **Учитывайте блокировку таблицы**: добавление индекса блокирует таблицу, поэтому это нужно учитывать при планировании операций.
- Используйте [[Профилирование запросов в PostgreSQL|EXPLAIN]]: для анализа статистики распределения данных и проверки эффективности выполнения запросов.
**Полезные советы:**
- [[../Селективность колонки|Селективность колонки]]: чем выше селективность, тем эффективнее работает индекс.
- **Частичные индексы**: используйте [[частичный индекс]], чтобы уменьшить размер индекса и повысить эффективность.
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[Индекс в PostgreSQL|Индекс в PostgreSQL]]
**Источник**::
**Создана**:: [[2024-10-21]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,27 @@
---
aliases:
tags:
- maturity/🌱
date: 2024-03-31
linked:
---
[[../Составные индексы в БД|Составные индексы]] в PostgreSQL позволяют ускорить выполнение запросов, в которых используются несколько колонок одновременно. Однако важно учитывать особенности их частичного использования.
При выполнении запроса составной индекс может использоваться до первого неравенства включительно. Это означает, что при встрече оператора неравенства (`>`, `<`, `>=`, `<=`) индекс перестает быть эффективным для последующих колонок.
Например, в запросе `a = 0 AND b > 3 AND c > 5` индекс будет использоваться для колонок `a` и `b`, но не для `c`, так как оператор неравенства для `b` ограничивает дальнейшее использование индекса.
- `a > 0 AND b = 4`: Индекс будет использоваться для всех колонок, несмотря на то, что первая часть — это неравенство.
- `a = 0 AND b > 3 AND c = 3`: Индекс будет использоваться для первых двух колонок. После неравенства индекс уже не применяется.
- `a = 0 AND b > 3 AND c > 3`: Индекс будет использоваться для первой и второй колонки.
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[../Составные индексы в БД|Составные индексы в БД]], [[Индекс в PostgreSQL]]
**Источник**::
**Автор**::
**Создана**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,38 @@
---
aliases:
- pg_stats
tags:
- maturity/🌱
date: 2024-03-31
---
Для получения статистики по определенной колонке используйте следующий запрос:
```sql
SELECT * FROM pg_stats WHERE tablename = 'your_table_name' AND attname = 'column_name';
```
Пример вывода:
![400](../../../meta/files/images/Pasted%20image%2020240331093839.png)
Самые полезные значения:
- **n_distinct**: Уникальность значений. Показывает, сколько уникальных значений содержится в колонке. Например, значение `-1` указывает, что количество уникальных значений составляет примерно 1% от общего количества строк.
- **correlation**: Упорядоченность значений. Значение близкое к 1 показывает, что значения упорядочены по возрастанию, а близкое к -1 — что по убыванию. Высокая корреляция помогает планировщику оптимизировать выполнение запросов, используя последовательное сканирование индексов.
- **most_common_vals** и **most_common_freqs**: Самые частые значения колонки и их частота. Эти данные помогают планировщику лучше оценить стоимость выполнения запросов и выбрать наиболее эффективный план.
- **null_frac**: Доля `NULL` значений. Например, значение 0.92 означает, что около 92% значений в колонке — `NULL`. Высокое значение `null_frac` может указывать на возможность создания частичного индекса для улучшения производительности.
> [!WARNING]
> Данные в `pg_stats` основаны на выборке, и поэтому могут не всегда точно отражать реальное состояние таблицы, особенно если данные часто изменяются. Для более точной оценки можно увеличить выборку строк с помощью настройки статистики
## Советы по анализу
- При большом значении `null_frac` остальные параметры могут иметь меньшее значение. На основе этой информации можно уменьшить размер индекса, создав [[Частичный индекс]].
- Если `n_distinct` показывает низкую уникальность, возможно, индекс на этой колонке не принесет значительного ускорения, так как слишком много строк имеют одинаковые значения (Низкая [[../Селективность колонки|селективность]]). В таком случае стоит рассмотреть пересмотр структуры запроса или таблицы.
- Высокое значение `correlation` (близкое к 1 или -1) означает, что данные отсортированы, что может существенно ускорить диапазонные запросы. В таких случаях планировщик может использовать последовательное сканирование, что может быть быстрее, чем случайное чтение.
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[Оптимизация SQL запросов в PostgreSQL]]
**Источник**::
**Автор**::
**Создана**:: [[2024-03-31]]
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,69 @@
---
aliases:
tags:
- maturity/🌱
date: 2024-10-21
---
Можно создать частичный индекс по условию, который покрывает только записи, удовлетворяющие определенному условию `WHERE`.
Например, можно исключить из индекса по внешнему ключу (FK) значения `NULL`:
```sql
CREATE INDEX fk_not_null ON pgconf(fk_id)
WHERE fk_id IS NOT NULL;
```
При этом работа индекса не ускоряется, так как СУБД автоматически оптимизирует выполнение запроса. Однако, ==это позволит уменьшить размер индекса, что на больших объемах данных также может положительно сказаться на производительности.== Поиск в индексе размером 15 ГБ выполняется быстрее, чем в индексе на 200 ГБ.
**Преимущества:**
- **Уменьшение размера индекса**: Индекс включает только необходимые записи, что уменьшает его общий объём.
- **Ускорение запросов**: Частичный индекс может улучшить производительность запросов, особенно если он используется для выборки узко определённых данных.
- **Оптимизация операций обновления**: Поскольку индекс обновляется только для определённых строк, уменьшаются накладные расходы на запись и обновление данных.
**Недостатки:**
- **Ограниченная применимость**: Частичные индексы не всегда подходят, особенно для данных с высокой селективностью, где обычные индексы будут более эффективны.
- **Сложность настройки**: Необходимо тщательно выбирать условия `WHERE`, чтобы получить максимальную пользу от частичного индекса. Неправильный выбор условий может привести к ухудшению производительности.
**Когда использовать частичные индексы:**
- Когда необходимо уменьшить размер индекса за счёт исключения ненужных записей, что позволяет сэкономить место на диске и ускорить операции поиска.
- Когда таблица содержит большое количество записей с одинаковыми значениями (низкая [[../Селективность колонки|селективность]]), и вам нужно индексировать только те записи, которые имеют уникальные или более специфичные значения.
- В ситуациях, когда индекс нужен для работы с данными, которые соответствуют определённому условию, например, только "необработанные" записи.
## Таблицы с колонкой статуса
Часто в приложениях есть таблицы, которые содержат колонку статуса (`state`). Обычно статус разделяет записи на "обработанные" и "необработанные". Индекс нам часто нужен именно по необработанным данным. Создавая частичный индекс только по необработанным данным, мы можем ускорить выполнение запроса и уменьшить размер индекса.
Возьмем типичную табличку, в которой есть какие-то статусы мы хотим находить данные по этому статусу.
![300](../../../meta/files/images/Pasted%20image%2020240331095959.png)
![600](../../../meta/files/images/Pasted%20image%2020240331100144.png)
Часто появляется желание сделать индекс по полю статуса:
![600](../../../meta/files/images/Снимок%20экрана%202024-03-31%20в%2010.07.02.png)
Но по факту мы индексируем поле, которое имеет небольшую [селективность](../../dev/database/Селективность%20колонки.md). Такой индекс не эффективный.
Хороший вариант в данном случае:
![600](../../../meta/files/images/Снимок%20экрана%202024-03-31%20в%2010.13.39.png)
Почти идеальный:
![600](../../../meta/files/images/Снимок%20экрана%202024-03-31%20в%2010.15.06.png)
![500](../../../meta/files/images/Pasted%20image%2020240331101612.png)
Идеальный. Совмещаем и [[../../../dev/database/postgresql/Составной индекс в PostgreSQL|составной индекс]] и частичный.
![[../../../meta/files/images/Pasted image 20241021225124.png]]
***
## Мета информация
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
**Родитель**:: [[Индекс в PostgreSQL]], [[Оптимизация SQL запросов в PostgreSQL]]
**Источник**::
**Создана**:: [[2024-10-21]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -2,22 +2,25 @@
aliases:
tags:
- maturity/🌱
date:
- - 2024-05-26
date: 2024-05-26
zero-link:
- "[[00 Базы Данных]]"
parents:
linked:
---
Основная цель журнала — фиксировать все изменения, происходящие в базе данных, до их окончательного применения. Это позволяет выполнять [[../../../../_inbox/Транзакция БД|транзакции]] и [[../architecture/highload/Репликация БД|репликацию бд]].
Журнал базы данных — это структура, в которой фиксируются все изменения, происходящие в базе данных, до их окончательного применения. Основная цель журнала — обеспечить надежность и консистентность данных. Это позволяет выполнять [[Транзакция БД|транзакции]] и [[../architecture/highload/Репликация БД|репликацию БД]].
Перед тем как выполнить SQL-запрос, база данных записывает в журнал все действия, которые собирается сделать. После того как журнал зафиксировался на диске, база данных изменяет сами данные в памяти. И только через какое-то время эти данные окажутся на диске в хранилище. Этот алгоритм называется [PITR](Point%20In%20Time%20Recovery%20(PITR).md)
Перед выполнением SQL-запроса база данных сначала записывает в журнал информацию о планируемых действиях, например: "Обновить значение колонки `amount` в таблице `orders` для записи с `id = 5`". После фиксации записи в журнале база данных изменяет данные в памяти, чтобы ускорить обработку операций, а затем, с некоторой задержкой, записывает их на диск в основное хранилище. Этот подход улучшает производительность за счет уменьшения количества операций записи на диск, которые являются более медленными по сравнению с изменениями в памяти. В случае сбоя системы до записи данных на диск, изменения можно восстановить из журнала. Этот алгоритм называется [[../../../../_inbox/Point In Time Recovery (PITR)|PITR]] (Point In Time Recovery).
![](Pasted%20image%2020240528081137.png)
Этот процесс обеспечивает два важных аспекта:
- **Надежность**: В случае сбоя системы, данные можно восстановить из журнала до последнего зафиксированного состояния.
- **Надежность**: В случае сбоя системы данные можно восстановить из журнала до последнего зафиксированного состояния.
- **Консистентность**: Все транзакции, записанные в журнал, будут применены в базе данных в правильном порядке, что предотвращает потерю данных и сохраняет целостность системы.
**Недостатки**:
- Увеличение времени записи: каждая транзакция требует предварительной записи в журнал, что может замедлить выполнение операций.
- Потребление дискового пространства: журналы могут занимать значительное место, особенно в системах с высокой активностью.
> [!INFO]
> Журналы базы данных часто имеют циклическую структуру, где новые данные записываются поверх старых, когда журнал заполняется. Это позволяет эффективно использовать дисковое пространство и упрощает управление журналом.
@ -32,7 +35,7 @@ linked:
- Как сделать так, чтобы это работало быстрее?
- При чем тут репликация?
Для улучшения производительности желательно под журналы выделять отдельные жесткие диски. Чтобы у журнала был эксклюзивный доступ к ресурсам диска. Менее актуально для SSD.
Для повышения производительности рекомендуется выделять отдельные жесткие диски под журналы, чтобы у них был эксклюзивный доступ к ресурсам диска. Это менее актуально для SSD, так как у них значительно выше скорость чтения и записи, а также отсутствует проблема механического доступа, что делает их более эффективными для параллельной работы с данными.
***
## Мета информация
**Область**:: [[../../meta/zero/00 Базы Данных|00 Базы Данных]]

View File

@ -0,0 +1,75 @@
---
aliases:
- индексов
- индекс
- индексы
- индексирования
- индекса
tags:
- maturity/🌱
date: 2024-10-11
---
**Индекс** — это служебная структура данных, которая позволяет ускорить операции поиска, сортировки и фильтрации данных в реляционных базах данных. Индексы создаются для одного или нескольких столбцов таблицы, с целью [[Оптимизация SQL запросов|ускорения выполнения запросов к базе данных]].
Индексы обычно реализуются на основе различных структур данных, каждая из которых подходит для определённых типов запросов. Наиболее распространённые структуры данных для индексов:
- **B-деревья** ([[../fundamental/structure/B-tree|B-tree]]). Широко применяются для ускорения операций поиска, сортировки и диапазонных запросов.
- **Хэш-индексы.** Хорошо подходят для поиска по точным значениям, но неэффективны для диапазонных запросов.
- **GiST и R-деревья.** Используются для индексации пространственных данных, таких как координаты или географические объекты.
СУБД автоматически выбирает наиболее подходящий индекс для выполнения запроса. Важно следить за тем, чтобы индекс покрывал нужные столбцы и типы запросов, так как ==неправильный выбор индекса может замедлить выполнение запросов.==
**Польза:**
- **Ускорение запросов.** Индексы значительно ускоряют выполнение запросов, особенно для операций равенства, сравнений и сортировки данных.
- ример_: `SELECT * FROM employees WHERE department = 'HR';` — индекс на столбце `department` ускорит выполнение этого запроса.
- **Покрытие запросов.** В некоторых случаях индексы могут содержать все данные, необходимые для выполнения запроса, что позволяет избежать чтения самих строк таблицы (так называемый "[[Покрывающий индекс]]").
- ример_: `SELECT name, age FROM employees WHERE department = 'IT';` — если индекс покрывает столбцы `name`, `age` и `department`, то чтение строк таблицы не потребуется.
- **Поддержка ограничений.** Индексы могут использоваться для реализации ограничений на уникальность данных (UNIQUE), а также для обеспечения ссылочной целостности (FOREIGN KEY).
**Накладные расходы:**
- **Влияние на производительность**: добавление индексов замедляет операции вставки, обновления и удаления, так как индекс должен быть обновлен при каждой модификации данных. При создании индексов необходимо учитывать характер нагрузки на таблицу, особенно если часто выполняются операции записи. Например, при [[Online Transaction Processing|OLTP]] нагрузке чтение данных значительно преобладает над записью (80% чтения и 20% записи), что оправдывает использование индексов.
- **Блокировка таблицы**: добавление индекса блокирует таблицу, что может негативно сказаться на производительности, особенно в [[../../meta/zero/00 HighLoad|высоконагруженных системах]].
- **Дополнительное использование дискового пространства.** Индексы требуют значительного объема дискового пространства для хранения. Обычно объем индексов составляет около половины размера таблицы. Если размер индексов превышает размер таблицы, это может указывать на необходимость оптимизации.
- **Необходимость технического обслуживания.** Со временем индексы могут фрагментироваться и требовать пересоздания для поддержания эффективности. В некоторых системах управления базами данных (СУБД) это может происходить автоматически, однако в других случаях требуется ручное вмешательство.
**Частые ошибки:**
- **Низкая селективность.**: индексы на колонках с низкой [[Селективность колонки|селективностью]] могут оказаться неэффективными и не принести ожидаемого увеличения производительности.
- Индекс на столбце `gender` с двумя возможными значениями (`M`, `F`) не даст значительного выигрыша в производительности.
- **Неиспользуемые индексы**. Индексы, которые не используются, создают дополнительные накладные расходы на хранение и обслуживание. Рекомендуется периодически проверять активность индексов и удалять те, что не используются. Найти такие индексы поможет [[postgresql/pageinspect|pageinspect]].
- **Высокие накладные расходы.** В некоторых случаях затраты на обновление индексов могут превышать выгоды от их использования. Наличие большого количества индексов на одной таблице может вызвать накладные расходы и ухудшить производительность, особенно при частых изменениях данных.
**Когда индексы не работают:**
- **Использование вычисляемых выражений.** Например, выражение `WHERE column + 1 = 10` не будет эффективно использовать индекс. В таких случаях могут применяться специальные методы, такие как индексы по выражению или генерация вычисляемых колонок.
- ример_: Для выражения `column + 1` можно создать вычисляемый столбец и индексировать его.
- **Обработка большого количества записей.** Если запрос возвращает слишком много строк, использование индекса может быть неэффективным.
- **Агрегатные функции.** Лишь некоторые агрегатные функции, такие как `MIN()` и `MAX()`, могут эффективно использовать индексы.
- **Логические операторы.** Индексы хорошо работают с условиями, использующими логический оператор И (`AND`), но менее эффективны с логическим ИЛИ (`OR`):
- **Логические операторы.** Индексы хорошо работают с условиями, использующими логический оператор И (`AND`), но менее эффективны с логическим ИЛИ (`OR`).
- ример запроса с ИЛИ_: `SELECT * FROM tb WHERE a = 0 OR b = 0;` — в этом случае индексы для каждого столбца могут быть использованы независимо (индексы на `a` и `b`), но составной индекс по этим столбцам не будет работать эффективно.
**Какие бывают индексы?**
- **Уникальные и неуникальные.** Уникальные индексы обеспечивают уникальность значений в столбцах. Неуникальные индексы допускают повторяющиеся значения.
- **Простые и составные.** Простые индексы создаются для одного столбца, а [[Составные индексы в БД|составные]] — для нескольких столбцов.
- **Кластерные и некластерные.** Кластерные индексы определяют физическое расположение данных на диске, а некластерные индексы хранят указатели на строки таблицы.
**Реализации:**
- [[postgresql/Индекс в PostgreSQL|Индекс в PostgreSQL]]
- [[../../../../_inbox/Индекс в MySQL|Индекс в MySQL]]
***
## Мета информация
**Область**:: [[../../meta/zero/00 Базы Данных|00 Базы Данных]]
**Родитель**::
**Источник**::
**Создана**:: [[2024-10-11]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
<!-- SerializedQuery: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
- [[Индекс в PostgreSQL]]
- [[Индекс в MySQL]]
- [[Составные индексы в БД]]
- [[Покрывающий индекс]]
<!-- SerializedQuery END -->

View File

@ -33,7 +33,7 @@ linked:
***
## Мета информация
**Область**:: [[../../meta/zero/00 Базы Данных|00 Базы Данных]]
**Родитель**:: [[Производительность SQL запросов]]
**Родитель**:: [[Оптимизация SQL запросов]]
**Источник**::
**Создана**:: [[2024-10-11]]
**Автор**::

View File

@ -0,0 +1,53 @@
---
aliases:
- ускорения SQL запросов
tags:
- maturity/🌱
date:
- - 2024-07-13
linked:
---
- [[postgresql/Оптимизация SQL запросов в PostgreSQL|Оптимизация SQL запросов в PostgreSQL]]
**Где могут быть проблемы?**
- **Передача запроса от клиента**: задержка или проблемы при передаче могут негативно сказываться на производительности. [Пример при использовании IN](IN%20SQL.md#Проблемы%20производительности%20IN)
- **Сложный запрос**: сложные запросы с большим количеством условий могут долго парситься, замедляя выполнение.
- **Долгое вычисление плана**: при сложных операциях, таких как JOIN, оптимизатору может потребоваться много времени для выбора лучшего плана выполнения.
- **Исполнение и возврат результатов**: возврат больших объемов данных (например, нескольких гигабайт) значительно замедляет запрос.
**Как улучшить?**
- **Используйте индексы**: правильно настроенные [[Индекс в БД|индексы]] могут существенно ускорить выполнение.
- **Переписать запрос**: упростите запрос, разделите его на несколько меньших, если это возможно.
**Что невозможно улучшить**
- `count(*)`: Подсчет всех строк в таблице — это ресурсоемкая операция, так как требует полного сканирования таблицы. Вместо этого можно использовать приближенные значения из таблицы статистики, которые дают примерное представление и требуют меньше ресурсов.
- **JOIN на 300 таблиц**: Операции с таким количеством таблиц чрезвычайно ресурсоемки, так как оптимизатору требуется много времени для вычисления плана, а выполнение может потребовать значительных ресурсов памяти и процессора. Альтернативой может быть пересмотр структуры данных и использование денормализации для сокращения числа объединяемых таблиц.
- **Возврат 1 000 000 000 строк**: Возврат большого количества строк, таких как миллиард записей, требует огромных объемов ресурсов и времени на передачу. Лучше ограничить количество возвращаемых строк и использовать агрегированные данные, если это возможно.
## Индекс для внешнего ключа
Всегда [[Индекс для внешнего ключа таблицы БД|добавляйте индекс для внешнего ключа]]. Индексация внешних ключей позволяет ускорить операции обновления и удаления, так как база данных может быстро находить связанные записи. Это особенно важно для таблиц с большим объемом данных, где операции без индекса могут значительно замедлить производительность.
## Подзапросы и JOIN
В некоторых случаях подзапросы могут быть более производительными, чем использование `JOIN`, так как планировщик запросов может оптимизировать выполнение подзапроса отдельно. Однако это зависит от конкретного запроса и структуры данных, поэтому всегда стоит проверять план выполнения ([[postgresql/Профилирование запросов в PostgreSQL|EXPLAIN]]) и тестировать оба варианта.
## IN и BETWEEN
Использование `IN` иногда может быть быстрее, чем `BETWEEN`, так как оно позволяет базе данных более эффективно работать с множеством значений. Однако это утверждение не универсально и может зависеть от конкретной реализации СУБД и структуры данных. Рекомендуется проводить тестирование с реальными данными, чтобы определить наиболее эффективный вариант.
## Сортировка по значениям NULL
Старайтесь избегать сортировки по значениям `NULL`. Сортировка по `NULL` может добавить значительную нагрузку на базу данных, так как `NULL` требует специальной обработки, чтобы корректно определить порядок значений.
## Использование DISTINCT
Использование `DISTINCT` следует минимизировать, так как оно приводит к дополнительным вычислениям для удаления дублирующихся значений. Если возможно, попробуйте перепроектировать запрос или данные так, чтобы избежать необходимости в `DISTINCT`.
## OFFSET и производительность
Использование `OFFSET` для постраничного отображения данных снижает производительность, особенно на больших таблицах, так как база данных должна пропустить множество строк перед тем, как выбрать нужные. Рекомендуется использовать курсоры или другие способы для постраничного вывода, чтобы уменьшить нагрузку на базу данных.
***
## Мета информация
**Область**:: [[../../../../wiki/zero/00 SQL|00 SQL]]
**Родитель**::
**Источник**::
**Автор**::
**Создана**:: [[2024-07-13]]
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
<!-- SerializedQuery: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
- [[Индекс для внешнего ключа таблицы БД]]
- [[Оптимизация SQL запросов в PostgreSQL]]
<!-- SerializedQuery END -->

View File

@ -0,0 +1,29 @@
---
aliases:
- Сложный запрос
- плохие sql запросы
- проблемных запросов
- проблемный запрос
tags:
- maturity/🌱
date: 2024-10-21
---
Понимание того, что такое плохой или медленный запрос, важно для поддержания высокой производительности системы. Плохие запросы могут существенно замедлять работу базы данных, создавая нагрузку на сервер и снижая эффективность всех операций. Их [[Оптимизация SQL запросов|оптимизация]] позволяет значительно улучшить производительность, уменьшить задержки и снизить использование ресурсов.
**Признаки плохого запроса**
- Запрос, который выполняется медленнее, чем остальные, и значительно увеличивает время обработки.
- Запросы, которые по отдельности достаточно быстрые, но из-за частого выполнения и отсутствия оптимизации потребляют значительное количество ресурсов сервера.
- Запросы, которые создают блокировки, мешая другим операциям выполняться параллельно.
***
## Мета информация
**Область**:: [[../../../../wiki/zero/00 SQL|00 SQL]]
**Родитель**::
**Источник**::
**Создана**:: [[2024-10-21]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,47 @@
---
aliases:
- covering indexes
- покрывающего индекса
tags:
- maturity/🌱
date: 2024-06-09
---
Покрывающий индекс — это [[Индекс в БД|индекс]], который включает в себя все колонки, необходимые для выполнения определенного запроса, без необходимости обращения к основной таблице данных.
Обычный индекс позволяет ускорить поиск по ключевой колонке, но при этом, чтобы получить данные из других колонок, СУБД все равно обращается к основной таблице. ==Покрывающий индекс, в отличие от обычного, содержит все необходимые для запроса колонки, что исключает необходимость обращения к таблице и, следовательно, улучшает производительность.==
Пример создания покрывающего индекса в [[../../meta/zero/00 PostgreSQL|PostgreSQL]]:
```sql
CREATE INDEX idx_example ON table_name (column1) INCLUDE (column2);
```
Такой индекс включает колонку `column1` для индексирования и добавляет `column2`, которая не индексируется, но хранится рядом с индексом. Это позволяет выполнять следующий запрос, не обращаясь к основной таблице:
```sql
SELECT column1, column2 FROM table_name WHERE column1 = 'value';
```
**Преимущества**:
- Значительное улучшение производительности запросов, так как нет необходимости обращаться к основной таблице.
- Уменьшение числа обращений к диску, особенно для часто используемых запросов с выборкой нескольких колонок.
**Недостатки**:
- Покрывающие индексы могут занимать больше места в памяти, особенно если в них включены несколько дополнительных колонок.
- Увеличение времени на операции вставки, обновления и удаления, так как индекс требует обновления при изменениях данных.
**Покрывающие индексы стоит использовать в следующих случаях:**
- Для оптимизации часто выполняемых SELECT-запросов, которые выбирают несколько колонок.
- Когда необходимо минимизировать количество обращений к диску, чтобы ускорить выполнение запросов.
- Для [[Online Analytical Processing|OLAP]], где важно быстрое чтение данных без необходимости частых обновлений.
***
## Мета информация
**Область**:: [[../../meta/zero/00 Базы Данных|00 Базы Данных]]
**Родитель**:: [[Индекс в БД]]
**Источник**::
**Автор**::
**Создана**:: [[2024-06-09]]
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,37 @@
---
aliases:
- селективность
- селективные
- селективностью
tags:
- maturity/🌱
date: 2024-03-31
---
Селективность колонки в базе данных — это отношение уникальных значений в столбце к общему количеству значений. ==Чем больше уникальных значений, тем выше селективность.== Селективность выражается значением от 0 до 1, где 0 означает отсутствие селективности, а 1 — идеальную селективность.
Высокая селективность делает колонку отличным кандидатом для [[Индекс в БД|индексирования]], так как это уменьшает количество строк для просмотра и ускоряет поиск. Например, колонка с уникальными идентификаторами пользователей позволяет значительно улучшить производительность запросов.
Низкая селективность означает много повторяющихся значений. Например, колонка с полом пользователя ("мужской" и "женский"). Индекс на таком столбце обычно малоэффективен, но может быть полезен при использовании с другими более селективными колонками. Это помогает уменьшить объем данных для сканирования.
Также индексы на низкоселективных колонках могут ускорить выборку редких записей, например, необработанных данных.
```sql
SELECT * FROM records WHERE processed = false;
```
Если большинство записей уже обработаны, такой индекс может значительно ускорить запрос.
***
## Мета информация
**Область**:: [[../../meta/zero/00 Базы Данных|00 Базы Данных]]
**Родитель**::
**Источник**::
**Автор**::
**Создана**:: [[2024-03-31]]
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,68 @@
---
aliases:
- Составные индексы
tags:
- maturity/🌱
date: 2024-06-16
---
Составным называется индекс, который включает в себя сразу несколько полей. Он используется для повышения производительности запросов, которые фильтруют данные по нескольким колонкам одновременно.
==В составных индексах важен порядок столбцов.== Порядок колонок в индексе влияет на его эффективность, и более [[Селективность колонки|селективные]] поля должны идти первыми, чтобы максимизировать производительность. SQL-запросы также должны следовать этому порядку для оптимального использования индекса.
При поиске по составному индексу значения колонок сравниваются по порядку, что делает порядок следования колонок критически важным для эффективности запросов.
> [!WARNING] Количество параметров
> Составной индекс из 2-3 полей обычно считается нормальным и эффективно поддерживаемым. Если количество колонок в индексе превышает три, следует тщательно анализировать его использование, чтобы избежать излишней нагрузки на производительность.
**Преимущества:**
- **Оптимизация дискового пространства**: ==Один составной индекс может заменить несколько простых индексов==, что экономит дисковое пространство.
- **Ускорение запросов**: Составной индекс позволяет ускорять запросы, которые используют несколько колонок для фильтрации и сортировки данных.
**Недостатки:**
- **Высокие накладные расходы при обновлении**: Каждый раз при вставке, обновлении или удалении данных, которые попадают в составной индекс, СУБД должна обновлять весь индекс, что может увеличивать время выполнения таких операций.
- Старайтесь минимизировать использование неравенств в начале составных индексов, так как это может ограничить их применение для последующих колонок.
Создание составного индекса:
```sql
CREATE INDEX idx_example ON table_name (column_a, column_b);
```
Запросы, которые могут использовать этот индекс:
Фильтрация по обоим полям:
```sql
SELECT * FROM orders WHERE customer_id = 123 AND order_date >= '2024-01-01';
```
Этот запрос будет максимально эффективен, так как учитывает оба поля в порядке, указанном в индексе.
Фильтрация только по `customer_id`:
```sql
SELECT * FROM orders WHERE customer_id = 123;
```
Этот запрос также будет использовать индекс, поскольку `customer_id` — первая колонка в составном индексе.
Запрос, который не будет оптимально использовать составной индекс:
```sql
SELECT * FROM orders WHERE order_date >= '2024-01-01';
```
Такой запрос не использует весь потенциал индекса, так как `order_date` не является первой колонкой.
***
## Мета информация
**Область**:: [[../../meta/zero/00 Базы Данных|00 Базы Данных]]
**Родитель**:: [[Индекс в БД]]
**Источник**::
**Автор**::
**Создана**:: [[2024-06-16]]
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
<!-- SerializedQuery: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
- [[Составной индекс в PostgreSQL]]
<!-- SerializedQuery END -->

View File

@ -2,20 +2,14 @@
aliases:
tags:
- maturity/🌱
- content/problem
date: 2023-11-02
zero-link:
parents:
linked:
---
## Проблема
==При создании VIEW в Liquibase возникают проблемы с её поддержкой, поскольку она часто изменяется, особенно когда меняется исходная таблица, используемая вьюхой.== Проблемы усложняются, если к одной таблице привязано несколько вьюх.
При создании VIEW в [[../../../../knowledge/dev/Liquibase|Liquibase]] возникают трудности с её поддержкой, особенно когда исходная таблица, меняется. Это становится ещё сложнее, если несколько VIEW ссылаются на одну таблицу. Когда происходят изменения, становится сложно быстро найти актуальный скрипт для создания VIEW, так как изменения могут быть разбросаны по нескольким файлам или версиям.
После нескольких изменений становится сложно находить актуальный скрипт создания VIEW для его обновления, так как изменения могут быть разбросаны по нескольким файлам или версиям. Например, изменения в логике могут быть внесены в один файл, а изменения в структуре — в другой, что затрудняет сборку актуальной версии скрипта.
## Решение
Для решения этой проблемы все VIEW выносятся в отдельный changeLog файл. Этот changeLog файл всегда указывается в конце master changeLog, так как вьюхи создаются после создания всех необходимых таблиц и данных в базе, чтобы обеспечить их корректность.
Для упрощения управления все VIEW выносятся в отдельный changeLog файл. Этот файл всегда указывается в конце основного master changeLog, поскольку VIEW создаются после создания всех таблиц, чтобы обеспечить корректность их работы.
Пример master changeLog файла:
```xml
<?xml version="1.1" encoding="UTF-8"?>
<databaseChangeLog
@ -32,15 +26,7 @@ linked:
</databaseChangeLog>
```
В changeLog файле для создания вьюх необходимо придерживаться следующего порядка:
- Сначала идет changeSet, который удаляет вьюху, если она уже существует.
- Затем идет changeSet, который создает новую вьюху.
Важным здесь является указывание следующий параметров changeSet-а:
- `runAlways="true"` — указывает Liquibase всегда выполнять этот changeSet, даже если он был уже выполнен ранее. Это особенно полезно, когда необходимо поддерживать актуальность данных вьюхи после каждого изменения.
- `runOnChange="true"` — указывает Liquibase игнорировать несовпадение контрольной суммы данного changeSet-а. Это важно, когда вносятся изменения в структуру вьюхи, и необходимо обновить её без возникновения ошибок из-за изменения контрольной суммы.
Пример changeSet-ов.
Пример `views/changelog.xml`:
```xml
<?xml version="1.0" encoding="UTF-8"?>
@ -66,10 +52,19 @@ linked:
...SQL FOR CREATE VIEW...
</createView>
</changeSet>
</databaseChangeLog>
```
Таким образом, у нас появляется единое место, которое содержит актуальные структуры наших VIEW.
В файле changeLog для управления вьюхами необходимо соблюдать следующий порядок:
- Сначала используется changeSet, который удаляет вьюху, если она уже существует.
- Затем используется changeSet, который создаёт новую вьюху.
Ключевыми параметрами для changeSet являются:
- `runAlways="true"` — указывает Liquibase всегда выполнять данный changeSet, даже если он уже выполнялся ранее. Это важно для поддержания актуальности данных вьюхи после каждого изменения.
- `runOnChange="true"` — указывает Liquibase игнорировать изменения контрольной суммы для данного changeSet.
Таким образом, вы получите централизованное и актуальное место для управления структурами VIEW, что значительно упростит их поддержку и обновление.
***
## Мета информация
**Область**:: [[../../meta/zero/00 Базы Данных|00 Базы Данных]]

View File

@ -0,0 +1,79 @@
---
aliases:
tags:
- maturity/🌱
date: 2024-04-07
---
Одним из самых эффективных способов ускорить работу веб-сервера Nginx является включение GZIP-сжатия. GZIP обеспечивает сжатие без потерь, что означает, что исходные данные можно полностью восстановить при распаковке. Сжатие основано на алгоритме [DEFLATE](https://ru.wikipedia.org/wiki/Deflate), который сочетает в себе алгоритмы [LZ77](https://ru.wikipedia.org/wiki/LZ77) и [Хаффмана](https://ru.wikipedia.org/wiki/Код_Хаффмана).
Большинство современных клиентов и серверов поддерживают GZIP. Когда браузер или другой клиент, совместимый с GZIP, запрашивает ресурс у сервера с поддержкой GZIP, сервер сжимает ответ перед отправкой. Это позволяет значительно уменьшить объем передаваемых данных и ускорить загрузку страниц.
Пример конфигурации для включения GZIP-сжатия в Nginx. Откройте основной файл конфигурации `/etc/nginx/nginx.conf` и добавьте следующие директивы в блок `http`:
```nginx
http {
...
gzip on;
gzip_min_length 500;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/javascript application/javascript application/x-javascript text/xml application/xml application/xml+rss application/json;
gzip_disable "msie6";
gzip_comp_level 6;
gzip_buffers 16 8k;
...
}
```
`gzip` — включает сжатие GZIP на сервере.
`gzip_min_length` — устанавливает минимальный размер ответа, для которого будет применяться сжатие. По умолчанию значение равно 20 байтам, но имеет смысл установить большее значение (например, 500 байт), так как ==сжатие слишком маленьких файлов может создать ненужную нагрузку на процессоры сервера и клиента.==
`gzip_vary` — добавляет заголовок `Vary: Accept-Encoding` в ответ сервера. Это позволяет кэшировать как сжатые, так и несжатые версии одного ресурса в зависимости от того, поддерживает ли клиент GZIP-сжатие.
`gzip_proxied` — определяет, нужно ли сжимать ответы для проксированных запросов в зависимости от их содержимого. Запрос считается проксированным, если в его заголовке присутствует поле Via. Можно указать несколько условий для применения сжатия:
> [!NOTE]- Параметры `gzip_proxied`
`off` отключает сжатие для всех проксированных запросов.
>
>`expired` разрешает сжатие, если в заголовке ответа есть поле Expires, запрещающее кэширование.
>
>`no-cache` сжатие разрешено, если в заголовке ответа есть поле Cache-Control с параметром no-cache.
>
>`no-store` сжатие разрешено, если в заголовке ответа есть поле Cache-Control с параметром no-store.
>
>`private` разрешает сжатие, если в заголовке ответа есть поле Cache-Control с параметром private.
>
>`no_last_modified` разрешает сжатие, если в заголовке ответа отсутствует поле Last-Modified.
>
>`no_etag` разрешает сжатие, если в заголовке ответа нет поля ETag.
>
>`auth` сжатие разрешено, если в заголовке запроса есть поле Authorization.
>
>`any` разрешает сжатие для всех проксированных запросов без ограничений.
>
>`gzip_types` по умолчанию включено сжатие для ответов типа текст. В данном параметре можно перечислить все необходимые типы ответов.
>
>`gzip_disable` запрещает для перечисленных параметров заголовка User-Agent сжатие. В данном примере для Internet Explorer 6 сжатие применяться не будет, так как данный браузер не умеет принимать сжатые ответы.
`gzip_types` — задает список типов MIME, для которых будет применяться сжатие. По умолчанию GZIP включен для ответов типа text/\*. В данном примере сжатие включено для текстовых файлов, CSS, JavaScript и JSON.
`gzip_disable` — отключает сжатие для определенных клиентов. В данном примере сжатие отключено для браузера Internet Explorer 6 (определяется по значению User-Agent), так как этот браузер не поддерживает работу с GZIP-ответами.
`gzip_comp_level` — устанавливает уровень сжатия. Рекомендуемое значение — 6, так как оно обеспечивает баланс между скоростью сжатия и эффективностью (по умолчанию уровень сжатия равен 1, а максимальный — 9).
`gzip_buffers` — задает количество и размер буферов для хранения сжатых данных перед отправкой клиенту. В данном случае установлено 16 буферов по 8К.
***
## Мета информация
**Область**:: [[../../../meta/zero/00 Nginx|00 Nginx]]
**Родитель**:: [[../../algorithm/GZIP|GZIP]]
**Источник**::
**Автор**::
**Создана**:: [[2024-04-07]]
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,69 @@
---
aliases:
tags:
- maturity/🌱
date: 2024-04-07
---
Для повышения производительности можно кэшировать ответы на запросы на стороне Nginx, которые редко изменяются. Это позволяет серверу один раз получить результат от вашего приложения и в дальнейшем возвращать его другим клиентам, снижая нагрузку на приложение.
Для начала необходимо создать директорию, в которой будут храниться данные кэша:
```shell
sudo mkdir -p /var/nginx/cache
```
После этого, в основной конфигурационный файл `nginx.conf` нужно добавить несколько директив:
```nginx
http {
proxy_cache_path /var/nginx/cache levels=1:2 keys_zone=nginxcash:60m max_size=256m inactive=24h;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_methods GET HEAD;
proxy_cache_min_uses 2;
}
```
`proxy_cache_path` — указывает путь к директории, где будут храниться кэшированные данные.
- Параметр `levels` задает структуру папок для хранения кэша, keys_zone определяет размер зоны для хранения метаданных (в данном случае 60 мегабайт).
- `max_size=256m` задает максимальный размер кэша.
- `inactive=24h` указывает, что кэшированные данные, к которым не было обращений в течение 24 часов, будут автоматически удалены.
`proxy_cache_key` — определяет ключ кэширования. В данном случае используется комбинация схемы запроса, метода, хоста и URI. Этот ключ позволяет разделить кэш для разных поддоменов и запросов.
`proxy_cache_methods` — указывает, какие HTTP-методы будут кэшироваться (в данном примере — только методы GET и HEAD).
`proxy_cache_min_uses` — задает минимальное количество обращений к ресурсу перед его кэшированием. Установка значения 2 означает, что кэширование начнется только после второго обращения, что предотвращает кэширование редко используемых данных и снижает нагрузку на запись.
## Переносим кэш Nginx в RAM
Чтобы значительно ускорить кэш, можно разместить его в оперативной памяти (RAM) вместо файловой системы. Это позволит значительно сократить время доступа к кэшированным данным.
Для этого создаем директорию для кэша (если она уже создана, нужно очистить её от содержимого) и монтируем её в RAM с помощью [tmpfs](https://wiki.archlinux.org/index.php/Tmpfs). Выделим 256 мегабайт под кэш:
```shell
sudo mount -t tmpfs -o size=256M tmpfs /var/nginx/cache
```
Если потребуется отключить RAM-кэш, выполните команду:
```shell
sudo umount /var/nginx/cache
```
Чтобы автоматически пересоздавать кэш в RAM после перезагрузки системы, необходимо обновить файл `/etc/fstab`. Добавьте в него следующую строку:
```txt
tmpfs /var/nginx/cache tmpfs defaults,size=256M 0 0
```
***
## Мета информация
**Область**:: [[../../../meta/zero/00 Nginx|00 Nginx]]
**Родитель**:: [[../../architecture/Кэширование|Кэширование]]
**Источник**::
**Автор**::
**Создана**:: [[2024-04-07]]
### Дополнительные материалы
- [Оптимизация NGINX](https://struchkov.dev/blog/ru/nginx-optimization/)
- [Nginx cache: всё новое — хорошо забытое старое / Хабр](https://habr.com/ru/post/428127/)
- [[../../devops/nginx/Кэширование статики в Nginx|Кэширование статики в Nginx]]
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,38 @@
---
aliases:
tags:
- maturity/🌱
date: 2024-04-07
---
Чтобы настроить кэширование статического контента, можно добавить следующие директивы в основной конфигурационный файл Nginx:
```nginx
server {
...
# Media
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|mp4|ogg|ogv|webm|htc)$ {
expires 30d;
}
# CSS and Js
location ~* \.(css|js|woff2)$ {
expires 365d;
}
...
}
```
В этом примере медиа-файлы, такие как изображения и видео, будут кэшироваться на 30 дней, а файлы CSS, JS и шрифты — на 365 дней.
***
## Мета информация
**Область**:: [[../../../meta/zero/00 Nginx|00 Nginx]]
**Родитель**:: [[../../architecture/highload/Кэширование на стороне браузера|Кэширование на стороне браузера]]
**Источник**::
**Автор**::
**Создана**:: [[2024-04-07]]
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -4,11 +4,6 @@ aliases:
tags:
- maturity/🌱
date: 2024-09-17
zero-link:
- "[[../garden/ru/meta/zero/00 Разработка|00 Разработка]]"
parents:
- "[[structure/Структура данных]]"
linked:
---
Дерево — это иерархическая структура данных, состоящая из узлов (вершин), которые связаны друг с другом ребрами. Главные характеристики деревьев:
- Корень: Узел, с которого начинается дерево. У него нет родительского узла.
@ -27,7 +22,7 @@ linked:
***
## Мета информация
**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]]
**Родитель**:: [[structure/Структура данных]]
**Родитель**:: [[structure/Структура данных|Структура данных]]
**Источник**::
**Создана**:: [[2024-09-17]]
**Автор**::

View File

@ -2,67 +2,59 @@
aliases:
tags:
- maturity/🌱
date:
- - 2024-01-29
zero-link:
parents: []
linked:
date: 2024-01-29
---
[Сбалансированное](structure/Сбалансированное%20дерево.md) сильно-ветвистое дерево. Позволяет хранить в узле множество значений.
[[Сбалансированное дерево|Сбалансированное]] сильно-ветвистое дерево позволяет хранить в узле множество значений, что делает его эффективным для работы с большими объемами данных.
![](../../../meta/files/images/Pasted%20image%2020240205190752.png)
- Узел содержит множество элементов.
- Каждый узел является по факту страничкой на диске, это позволяет уменьшить издержки на чтение с диска.
- В каждом узле есть ссылка на следующий и предыдущий узел (B+tree).
- В узлах дерева лежат либо данные, либо указатель на данные.
В таком дереве есть параметр t - минимальная степень. От этого параметра зависит, сколько будет храниться элементов в 1 узле дерева. В каждом узле должно храниться не мене t-1 ключе, и не более 2t-1. Правильно не выполняется для корневого значения.
Какое t использовать?
- Больше t -> меньше высота дерева
- зависит от размера блока на диске
- зависит от объема ОЗУ
- Обычно t выбирается от 50 до 2000.
- t = 1001 и 1 млрд. записей => 3 операции для любого ключа
Элементы в узле бинарного дерева отсортированы.
Большое количество элементов в узле позволяет делать деревья с большим количеством элементов, но с небольшой высотой.
**Основные особенности B-tree**
- Узел содержит множество элементов, что позволяет хранить больше данных в одном месте.
- Каждый узел представляет собой [[../Страница|страничку]] на диске, что снижает издержки на чтение.
- В каждом узле есть ссылки на следующий и предыдущий узлы (характерно для B+tree).
- В узлах дерева могут храниться сами данные или указатели на данные.
- Элементы в узле отсортированы, что делает поиск более эффективным и позволяет создавать деревья с небольшой высотой, тем самым уменьшая количество обращений к диску.
- Значения в узлах могут быть не уникальными.
## Параметр t
Параметр `t` определяет количество элементов в узле дерева.
- В каждом узле должно быть не менее `t-1` и не более `2t-1` ключей. Это правило важно для поддержания сбалансированности дерева, так как позволяет равномерно распределять элементы между узлами и поддерживать эффективную высоту дерева, что, в свою очередь, обеспечивает высокую производительность операций поиска.
- Это правило не выполняется для корневого узла.
**Как выбрать `t`**: значение `t` влияет на высоту дерева — ==большее значение уменьшает высоту, что снижает количество обращений к диску.== Обычно `t` выбирается в диапазоне от 50 до 2000 в зависимости от размера блока на диске и объема [[../../../../../knowledge/dev/pc/Оперативная память|оперативной памяти]]. Например, при `t = 1001` и 1 млрд записей требуется всего 3 операции для поиска любого ключа.
## Применение B-tree
**С чем может помочь:**
- Поиск по равенству (a=5)
- Поиск по открытому диапазон (a > 5 или a < 3)
- Поиск по закрытому диапазону (3 < a < 8)
- LIKE тоже работает с индексами, но только по префиксам
- LIKE 'a%' - хорошо
- LIKE '%c' - плохо
- **Поиск по равенству**: `a = 5`
- **Поиск по открытому диапазону**: `a > 5` или `a < 3`
- **Поиск по закрытому диапазону**: `3 < a < 8`
- **LIKE** работает с индексами по префиксам (`LIKE 'a%'` — эффективно)
**С чем НЕ поможет:**
- Искать четные/нечетные числа
- Искать суффиксы. LIKE '%c' - плохо
- Поиск четных или нечетных чисел.
- Поиск суффиксов (`LIKE '%c'` — неэффективно).
## Поиск в B-tree
Пример поиска 27.
Рассмотрим пример поиска значения `27`.
![](../../../meta/files/images/Pasted%20image%2020240129193115.png)
Важно. Значения в узлах могут быть не уникальными. Например, могло быть 2 числа 27. В таком случае поиск продолжается. При этом стоит учитывать, что количество элементов внутри узла ограничено, а значит следующий элемент (27) может находится в следующем узле. Поэтому для оптимизации этой проблемы блоки на одном уровне линкуют, создавая связный список, чтобы легко перейти в следующий блок.
- алгоритм аналогичен [бинарному дереву](structure/Бинарное%20дерево%20поиска.md), но выбор не из 2-ух, а из нескольких
- поиск за O(t logt(n))
- Но обращений к диску O(logt(n))
Значения в узлах могут быть не уникальными. Например, если значение `27` встречается дважды, поиск продолжается, переходя в следующий узел. Чтобы облегчить этот процесс, блоки на одном уровне связаны, создавая связный список.
Алгоритм поиска аналогичен [[Бинарное дерево поиска|бинарному дереву]], но выбор осуществляется из нескольких вариантов, а не из двух. Поиск выполняется за `O(t logt(n))`, но количество обращений к диску — `O(logt(n))`.
## Добавление в B-tree
Представим, что у нас уже есть вот такое дерево, и нам надо вставить в него значение 15
Представим, что нужно вставить значение `15` в уже существующее дерево.
![](../../../meta/files/images/Pasted%20image%2020240129194120.png)
Мы понимаем, что вставка должна быть между 4 и 17, там у нас есть узел 7...16. Но в него мы вставить не можем, так как в данном случае у нас t = 3, а значит в блоке не должно быть больше 5 значений.
Поэтому блок разбивается начиная с t-1 элементу. В данном случае это 11. Элемент, по которому разбивается блок перемещается в родительский блок. Если в родительском блоке происходит переполнение, то родительский блок тоже разбивается и так далее.
Вставка должна произойти между значениями `4` и `17`. Узел `7...16` переполнен (t = 3, максимум 5 значений), поэтому узел разбивается начиная с `t-1` элемента (в данном случае `11`). Элемент, по которому происходит разбиение, перемещается в родительский узел. Если родительский узел переполняется, он тоже разбивается, и так далее.
После вставки мы получим следующее дерево
![](../../../meta/files/images/Pasted%20image%2020240129194629.png)
## Удаление из B-tree
Удаление элемента из B-tree требует поддержания минимального количества ключей в узле для сохранения сбалансированности дерева и его эффективной высоты. Например, при удалении элемента, если количество ключей в узле становится меньше `t-1`, выполняется перераспределение элементов из соседних узлов или их слияние, чтобы поддерживать сбалансированность. Существует несколько сценариев удаления:
- **Удаление из листового узла**: Если элемент находится в листовом узле и после его удаления остается не менее `t-1` элементов, узел остается без изменений.
- **Удаление из внутреннего узла**: Если удаляемый элемент находится во внутреннем узле, он заменяется на наибольший элемент в левом поддереве или наименьший элемент в правом поддереве. После этого выполняется удаление из листового узла.
- **Перераспределение и слияние узлов**: Если после удаления в узле остается меньше `t-1` элементов, выполняется перераспределение элементов из соседнего узла или слияние с соседним узлом.
***
## Мета информация
**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]], [[../../../meta/zero/00 Алгоритм|00 Алгоритм]]

View File

@ -4,27 +4,43 @@ aliases:
- бинарному дереву
tags:
- maturity/🌱
date:
- - 2024-01-29
zero-link:
- "[[../../../meta/zero/00 Разработка|00 Разработка]]"
parents:
linked:
date: 2024-01-29
---
Дерево у которого выполняется 3 свойства
- элемент в левом под-дереве должны быть меньше родительского узла
- элементы в правом под-дереве должны быть больше родительского узла
- у каждого узла не больше 2 потомков
Бинарное дерево поиска — это [[структура данных]], в которой выполняются три свойства:
- Элементы в левом поддереве должны быть меньше родительского узла.
- Элементы в правом поддереве должны быть больше родительского узла.
- У каждого узла не больше двух потомков.
![x|400](../../../meta/files/images/Pasted%20image%2020240129190639.png)
Эти свойства дают
- гарантированный порядок элементов
- детерминированный алгоритм поиска
- в вырожденном случае придется посетить все элементы O(n).
**Эти свойства обеспечивают:**
- Гарантированный порядок элементов.
- Детерминированный алгоритм поиска.
- В вырожденном случае придется посетить все элементы — сложность O(n).
Чтобы улучшить поиск, можно использовать [сбалансированное](Сбалансированное%20дерево.md) бинарное дерево.
> [!TIP] Сбалансированное дерево
> Чтобы улучшить поиск, можно использовать [сбалансированное](Сбалансированное%20дерево.md) бинарное дерево.
**Сложность операций**
- **Средний случай**: поиск, вставка и удаление выполняются за O(log n), если дерево сбалансировано.
- **Худший случай**: если дерево становится несбалансированным, операции могут иметь сложность O(n). Это происходит, когда элементы добавляются в возрастающем или убывающем порядке, превращая дерево в цепочку.
## Основные операции с бинарным деревом поиска
### Вставка
При вставке нового элемента в бинарное дерево поиска он помещается в соответствующее место таким образом, чтобы сохранялся порядок элементов. Например, если вставляется значение `15`, и оно меньше текущего узла, оно вставляется в левое поддерево, иначе — в правое.
### Удаление
Удаление элемента из бинарного дерева поиска может потребовать нескольких шагов, чтобы сохранить его свойства:
- **Удаление листа**: просто удаляется узел.
- **Удаление узла с одним потомком**: узел заменяется своим потомком.
- **Удаление узла с двумя потомками**: узел заменяется минимальным значением в правом поддереве или максимальным значением в левом поддереве.
### Поиск
Поиск элемента в бинарном дереве поиска выполняется путем рекурсивного или итеративного перехода по узлам, начиная с корня. Если искомое значение меньше текущего узла, поиск продолжается в левом поддереве, если больше — в правом.
### Обход дерева
- **In-order обход**: обходит узлы в порядке возрастания значений. Используется для получения отсортированного списка элементов дерева.
- **Pre-order обход**: сначала посещается корень, затем левое и правое поддеревья. Полезно для копирования дерева.
- **Post-order обход**: сначала посещаются оба поддерева, затем корень. Используется для удаления дерева.
***
## Мета информация
**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]]

View File

@ -4,22 +4,59 @@ aliases:
- сбалансированное
tags:
- maturity/🌱
date:
- - 2024-01-29
zero-link:
parents: []
linked:
date: 2024-01-29
---
Сбалансированное дерево позволяет уменьшить сложность поиска в дереве. В сбалансированном дереве высота левого и правого дерева отличается не больше, чем на единицу.
Сбалансированное [[../Tree|дерево]] — это [[структура данных]], в которой высота левого и правого поддеревьев каждого узла отличается не более чем на единицу. Это позволяет сохранять логарифмическую сложность поиска (O(log n)), что делает его эффективным для операций поиска, вставки и удаления.
Балансировка заключается в
В несбалансированном дереве, например, при последовательном добавлении элементов в возрастающем порядке, дерево может превратиться в цепочку, что ухудшает производительность поиска до O(n). Сбалансированное дерево решает эту проблему, сохраняя высоту минимальной.
![](../../../meta/files/images/Pasted%20image%2020240129191116.png)
Сбалансированное дерево
- решает проблему вырожденного случая бинарного дерева
- дает поиск за O(высоты дерева)
- но требует дополнительных усилий на балансировку
**Плюсы**:
- Быстрая операция поиска — O(высоты дерева), что близко к O(log n) для сбалансированного дерева.
- Решает проблему вырожденного случая бинарного дерева.
**Минусы**:
- Требует дополнительных усилий и вычислительных ресурсов для поддержания балансировки, особенно при частых вставках и удалениях.
- В некоторых случаях операции вставки и удаления могут быть медленнее, чем в несбалансированных деревьях, из-за необходимости балансировки.
**Типы сбалансированных деревьев**
- **AVL-дерево**: Обеспечивает балансировку после каждой операции добавления или удаления. Высота левого и правого поддеревьев каждого узла отличается не более чем на единицу. AVL-деревья подходят для приложений, где важна быстрая операция поиска.
- **Красно-черное дерево**: Менее строгое, чем AVL-дерево, что делает его более быстрым для операций вставки и удаления. Красно-черные деревья используются в реализациях словарей и ассоциативных массивов.
**Алгоритмы балансировки**
- **Повороты**: Основной метод балансировки — это повороты (левое и правое). Они позволяют перераспределить элементы дерева так, чтобы сохранить его сбалансированность.
- **Перераспределение и слияние узлов**: Эти методы используются в зависимости от типа сбалансированного дерева для поддержания его свойств.
## Пример балансировки дерева
Представим, что добавляется новый элемент `30` в уже существующее AVL-дерево, и дерево становится несбалансированным:
```
20
/ \
10 25
```
После добавления `30` дерево становится несбалансированным, так как правое поддерево узла `25` становится слишком высоким:
```
20
/ \
10 25
\
30
```
Чтобы восстановить баланс, выполняется левое вращение относительно узла `25`, и дерево принимает следующий вид:
```
20
/ \
10 30
/
25
```
Таким образом, балансировка восстанавливает равновесие дерева и сохраняет его свойства. Например, если левое поддерево стало значительно выше правого, выполняется правое вращение для восстановления равновесия.
***
## Мета информация
**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]]

View File

@ -2,6 +2,7 @@
aliases:
- страницы
- страниц
- страничку
tags:
- maturity/🌱
date: 2024-09-17

View File

@ -25,7 +25,7 @@ linked:
Одним из ключевых преимуществ JPMS является чёткий контроль зависимостей. В старой системе через classpath все классы и пакеты были доступны друг другу без явного указания разрешений, что часто приводило к ошибкам и некорректному использованию библиотек. С JPMS разработчики могут точно указывать, какие зависимости нужны модулю и какие его части будут видимы другим модулям.
## Дескриптор
Каждый модуль имеет дескриптор - файл `module-info.java`, который содержит описание того, какие зависимости необходимы модулю и какие пакеты он экспортирует для других.
Каждый модуль имеет дескриптор - файл `module-info.java`, который содержит описание того, какие зависимости необходимы модулю и какие пакеты он экспортирует для других. Этот файл должен быть размещен в папке `src/main/java`.
Дескриптор описывает:
- Импортируемые, экспортируемые, транзитивно-экспортируемые пакеты.
@ -38,7 +38,7 @@ module com.example.myapp {
}
```
В этом примере модуль `com.example.myapp` использует (`requires`) модуль `java.sql` и экспортирует (`exports`) пакет `com.example.myapp.service`, который может быть использован другими модулями. Все остальные пакеты, не указанные в директиве `exports`, остаются приватными и недоступными для других модулей.
В этом примере модуль называется `com.example.myapp` и он использует (`requires`) модуль `java.sql` и экспортирует (`exports`) пакет `com.example.myapp.service`, который может быть использован другими модулями. Все остальные пакеты, не указанные в директиве `exports`, остаются приватными и недоступными для других модулей.
> [!NOTE] Обратная совместимость
> Модульная система разработана с учётом совместимости с предыдущими версиями JDK. Проекты, которые не перешли на JPMS, могут по-прежнему использовать старую систему через classpath.

View File

@ -0,0 +1,23 @@
---
aliases:
tags:
- maturity/🌱
date: 2024-10-21
zero-link:
parents:
linked:
---
***
## Мета информация
**Область**::
**Родитель**::
**Источник**::
**Создана**:: [[2024-10-21]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -0,0 +1,9 @@
---
tags:
- type/people
telegram:
work place:
position:
date: "[[2024-03-31]]"
aliases: []
---

View File

@ -11,7 +11,7 @@ title: MySQL
- [Репликация в MySQL](../../dev/database/mysql/Репликация%20в%20MySQL.md)
- [libslave](libslave.md)
- [Бекап в MySQL](Бекап%20в%20MySQL.md)
- [Индексы в MySQL](Индексы%20в%20MySQL.md)
- [Индекс в MySQL](../../../../_inbox/Индекс%20в%20MySQL.md)
- [Журналы в MySQL](../../dev/database/mysql/Журналы%20в%20MySQL.md)
- [Explain в MySQL](Explain%20в%20MySQL.md)
## Идентификация транзакций

40
meta/zero/00 Nginx.md Normal file
View File

@ -0,0 +1,40 @@
---
aliases:
- nginx
tags:
- type/zero-link
title: Nginx
---
Есть мастер процесс, который управляет асинхронными (В Apache воркеры были синхронные) воркерами. Количество воркеров, имеет смысл увеличивать количество воркеров до числа ядер в вашей системе, это отдельные процессы. Внутри воркера каждый воркер использует [неблокирующийся ввод-вывод](Не%20блокирующийся%20ввод-вывод.md) и [кооперативную многозадачность](../../dev/fundamental/Кооперативная%20многозадачность.md), чтобы обслужить большое количество одновременных соединений. Воркеры нужны только для того, чтобы распараллелиться между отдельными процессорами.
Nginx может также выступать в качестве [Rеverse proxy](../../dev/architecture/Rеverse%20proxy.md).
Узнать сколько и каких воркеров запущено можно командой. Обычно количество воркеров равно количеству ядер.
```
ps aux | grep nginx
```
## Плюсы nginx
- Умеет применять изменения конфига без перезапуска.
- Умеет обновлять саму версию nginx без остановки: сначала обновляются воркеры, когда все воркеры обновлены, обновляется мастер процесс.
## Конфигурация
- Вне зависимости от порядка location запрос будет обработан одинаково. Так как nginx ищет максимально возможное совпадение с префиксным location'ом, не заданным регулярным выражением, и после этого выбирает этот location. Используется конфигурация выбранного location'а, а все остальные location'ы игнорируются.
- Для регулярных выражений мы не можем определить максимальное совпадение, то выбирается location, у которого регулярное выражение совпало самым первым. ==То есть регулярные выражения добавляют зависимость от порядка, поэтому их стоит избегать==
- Правильный подход использование copy-paste, вместо попытки вынести общие части конфигурации. То есть, внутри location'а должны быть все необходимые директивы для его обработки.
- Rewrites **не** надо использовать вообще.
- Evil тоже не рекомендуемая конструкция в nginx, потому что, как работает внутри Evil, знает человек 10 в мире, и вы вряд ли входите в их число.
- Используйте if только для возврата какого-то ответа клиенту
## Оптимизация Nginx
- [Оптимизация работы соединений Nginx](Оптимизация%20работы%20соединений%20Nginx.md)
- [Кэширование на стороне Nginx](../../dev/devops/nginx/Кэширование%20на%20стороне%20Nginx.md)
- [Кэширование статики в Nginx](../../dev/devops/nginx/Кэширование%20статики%20в%20Nginx.md)
- [Балансировка запросов на Nginx](Балансировка%20запросов%20на%20Nginx.md)
- [GZIP сжатие в Nginx](../../dev/devops/nginx/GZIP%20сжатие%20в%20Nginx.md)
## Дополнительные материалы
- [Оптимизация NGINX](https://struchkov.dev/blog/ru/nginx-optimization/)
- [Масштабируемая конфигурация nginx](https://highload.guide/blog/scalable-configuration-nginx.html)
## Заметки
- Есть какой-то модуль, который позволяет отправлять события в [00 Kafka](00%20Kafka.md)

View File

@ -9,15 +9,16 @@ title: PostgreSQL
---
- Устройство PostgreSQL
- Журнал: [Write-Ahead Log](../../dev/database/postgresql/Write-Ahead%20Log.md)
- [Индекс в PostgreSQL](Индекс%20в%20PostgreSQL.md)
- [Индекс в PostgreSQL](../../dev/database/postgresql/Индекс%20в%20PostgreSQL.md)
- [Репликация в PostgreSQL](../../dev/database/postgresql/Репликация%20в%20PostgreSQL.md)
- [Бэкап в PostgreSQL](Бэкап%20в%20PostgreSQL.md)
- [Профилирование запросов в PostgreSQL](Профилирование%20запросов%20в%20PostgreSQL.md)
- [Explain в PostgreSQL](Explain%20в%20PostgreSQL.md)
- [Профилирование запросов в PostgreSQL](../../dev/database/postgresql/Профилирование%20запросов%20в%20PostgreSQL.md)
## Заметки
- PostgreSQL пишет на диск в два места в хранилище данных и в журнал.
- Изменение данных не заменяет строчку физически в памяти, а добавляет новую версию строки. Устаревшие строки через какое-то время помечаются и в них пишутся новые данные.
- Если транзакции нужно выполнить операцию с данными, с которыми работает другая транзакция, то она может встать в очередь.
- В логи попадают не все запросы. Это настраивается конфигурационными параметрами. Если логировать все запросы, то просядет производительность.
## Дополнительные материалы
- [pg_utils](pg_utils.md)
- [pg_utils](../../dev/database/postgresql/pg_utils.md)

View File

@ -12,10 +12,10 @@ linked:
- [Журнал БД](../../dev/database/Журнал%20БД.md)
- [Репликация БД](../../dev/architecture/highload/Репликация%20БД.md)
- [Резервные копии БД](Резервные%20копии%20БД.md)
- [Транзакция БД](Транзакция%20БД.md)
- [[../../../../_inbox/Индекс в БД|Индекс в БД]]
- [[../../../../_inbox/Индекс в PostgreSQL|Индекс в PostgreSQL]]
- [[../../../../_inbox/Индексы в MySQL|Индексы в MySQL]]
- [Транзакция БД](../../dev/database/Транзакция%20БД.md)
- [[../../dev/database/Индекс в БД|Индекс в БД]]
- [[../../dev/database/postgresql/Индекс в PostgreSQL|Индекс в PostgreSQL]]
- [[../../../../_inbox/Индекс в MySQL|Индекс в MySQL]]
СуБД:
- [PostgreSQL](00%20PostgreSQL.md)
@ -31,7 +31,7 @@ linked:
Приложение работает неограниченное количество времени, с каждым днем количество данных в БД увеличивается. При возрастании объема запросы начинают отрабатывать медленнее, в таком случае возникает необходимость в применении [партиционирования](Партиционирование%20в%20БД.md) и [шардирования](../../../../_inbox/Шардирование%20БД.md).
- [Производительность SQL запросов](_inbox/Производительность%20SQL%20запросов.md)
- [Оптимизация SQL запросов](../../dev/database/Оптимизация%20SQL%20запросов.md)
## Заметки
- Классические СУБД хранят данные в двух местах: на диске и в памяти.
@ -39,4 +39,5 @@ linked:
- ![](Pasted%20image%2020240531082744.png)
- Часто думают, что реляционная таблица — это массив. Некоторые даже думают, что это двумерный массив. На самом деле, это гораздо более сложная штука. Это мультимножество набор определенного сорта кортежей, над которым не задано порядка. В SQL-таблице нет порядка. Это важно. И, как результат, когда вы делаете SELECT* из БД (просканировать все записи), результат выполнения запроса может меняться строчки могут быть в одном порядке, а могут и в другом. Про это нужно помнить.
- Профиль нагрузки на реляционную базу данных выглядит следующим образом: 80% запросов это чтение, 20% запросов это запись. Если запросов на запись больше, то возможно реляционная база данных вам не подходит.
- Обычно в БД имеется планировщик выполнения запроса и executor. Планировщик обычно опирается на ранее собранную статистику выполнения запросов.

View File

@ -7,3 +7,4 @@ title: Снипеты на bash
---
- [Сжатие изображений без потери качества](../../dev/snippet/Сжатие%20изображений%20без%20потери%20качества.md)
- [Преобразование изображений в Webp](../../dev/snippet/Преобразование%20изображений%20в%20Webp.md)
- [[../../../../knowledge/dev/snippet/Генерация dhparam|Генерация dhparam]]

View File

@ -0,0 +1,14 @@
---
date: 2024-10-21
aliases:
- Jpont 2022
---
**Организатор**:: [[../../meta/organizations/JUG Ru Group|JUG Ru Group]]
## Доклады
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Конференция, this.file.link) -->
<!-- SerializedQuery: LIST FROM [[]] WHERE contains(Конференция, this.file.link) -->
- [[Доклад. Индексы в PostgreSQL. Как понять, что создавать]]
<!-- SerializedQuery END -->

View File

@ -0,0 +1,144 @@
---
parents:
- "[[Java конференция Joker]]"
aliases:
tags:
- maturity/🌱
- type/source/lecture
- type/source/best
date: 2022-10-14
---
**Организатор**:: [[../../meta/organizations/JUG Ru Group|JUG Ru Group]]
**Конференция**:: [[../conference/Конференция. Jpont 2022|Jpont 2022]]
**Автор**:: [[../../meta/people/Сальников Андрей|Сальников Андрей]]
**Ссылка**:: [Андрей Сальников — Индексы в PostgreSQL. Как понять, что создавать - YouTube](https://www.youtube.com/watch?v=ju9F8OvnL4E)
***
![Андрей Сальников — Индексы в PostgreSQL. Как понять, что создавать - YouTube](https://www.youtube.com/watch?v=ju9F8OvnL4E)
***
**О чем доклад:** Любой разработчик знает, что индексы — это мощный инструмент, который может улучшить работу запросов в базе данных и, как следствие, сократить отклик приложения или сервиса на внешние запросы. Но опыт Андрея, как ДБА, показывает, что у разработчиков нет понимания, какой, когда и из каких соображений можно создавать индекс. Спикер приведет простые и понятные примеры, которые вы сможете легко повторить на своих реальных базах данных.
В докладе в основном говорится об [[../../dev/database/Online Transaction Processing|OLTP]] нагрузке и объем баз данных от 20 Гб до 10 Тб.
## Тезисы
-
## Конспект
Многие разработчики не проводят исследовательскую работу перед созданием индексов и создают их как считают правильно, и не всегда это мнение совпадает с реальностью.
Первым делом стоит ознакомиться с документаций: [PostgreSQL: Documentation: 16: CREATE INDEX](https://www.postgresql.org/docs/current/sql-createindex.html)
Прежде чем создавать индексы, нужно понять что такое индексы. Фактически это легализованные косты для [[../../dev/database/Оптимизация SQL запросов|ускорения SQL запросов]]. В PostgreSQL индекс для первичного ключа индекс создается автоматически.
**Какие накладные расходы от индексов?**
- Замедление операций вставки и обновлений. Так как необходимо будет перестраивать индекс при вставке новых значений. Но это должно быть не так страшно, так как профиль нагрузки на реляционную базу данных выглядит следующим образом: 80% запросов это чтение, 20% запросов это запись. Если запросов на запись больше, то возможно реляционная база данных вам не подходит.
- Дополнительные объемы дискового пространства для хранения индекса. Размер индексов на таблицу в половину размера таблицы считается нормальным и оптимальным. Если размер всех индексов таблицы приближается или становится больше, значит что-то идет не так.
- Усложненное технического обслуживание. Индексы пухнут и переодически их нужно пересоздавать. В каких-то СУБД это происходит автоматически. Пересоздание индекса сложный процесс и может повлечь недоступность сервиса.
При создании индекса нужно провести анализ. Иначе можно получить все накладные расходы, и не получить преимущества.
**Что нужно для создания индекса?**
- Ориентироваться только на продуктовое окружение, так как тестовые окружения не соответствуют реальности.
- Собрать статистику нагрузки на БД от запросов. Чтобы понять какие запросы действительно требуют оптимизации. - [[../../dev/database/Плохой SQL запрос|Плохой SQL запрос]]. Для этого можно использовать различные инструменты
- [[../../dev/database/postgresql/pg_stat_statements|pg_stat_statements]]
- pgBadger - использовать с осторожностью. Собирает статистику из логов. Но в логи попадают не все запросы.
- Иметь примеры запросов с параметрами. Это необходимо для проверки проведенных оптимизаций.
- Нужно уметь читать статистику распределения данных - [[../../dev/database/postgresql/Таблица статистик pg_stats|Таблица статистик pg_stats]]. Это нужно, чтобы понимать как планировщик БД будет строить план выполнения запроса.
- По умолчанию PostgrteSQL использует для сбора статистики только 30k строк из таблицы. Из-за этого статистика может расходиться с реальностью. И нужно уметь собирать более полную статистику вручную. Когда есть подозрения, что в статистике есть существенные промахи.
Далее идет описание типов индексов, которые есть в Postgres, и которые перечислены в моей заметке [[../../dev/database/postgresql/Индекс в PostgreSQL#Типы индексов|Индекс в PostgreSQL]].
Для OLTP нагрузки не стоит использовать параллельное выполнение запроса. Так как это значит, что мы забираем ядро процессора у другого запроса. В OLTP нагрузке каждый запрос должен выполняться на одном процессе так быстро, как только возможно.
## Практика
![](../../meta/files/images/Pasted%20image%2020240331092706.png)
![](../../meta/files/images/Pasted%20image%2020240331092753.png)
- У таблицы есть первичный (bigint) и внешний ключи.
- Таблица имеет колонки различных типов данных.
- Таблица ссылается сама на себя, но это сделано для удобства доклада. Те же самые выводы распространятся и на связи с другими таблицами.
- Количество кортежей 10_000_000
- Индекс по первичному ключу занял 1/4 (214 Mb) от размера таблицы (816 Mb)
### Удаляем строку
Удаляем строку по первичному ключу.
![600](../../meta/files/images/Pasted%20image%2020240331093028.png)
В удалении задействован первичный ключ, поэтому используется поиск по индексу. Но по итогу ==самый долгий этап это проверка внешних связей с таблицей==. По итогу запрос вроде бы быстрый, но он не оптимальный, он потребляет намного больше ресурсов сервера, чем должен.
Под капотом для поиска внешних связей используется полное сканирование таблицы (Seq Scan). В данном примере специально включено паралеллельное выполнение, но это все равно занимает много времени.
![600](../../meta/files/images/Снимок%20экрана%202024-03-31%20в%2009.32.34.png)
Поэтому важно не забывать [[../../dev/database/Индекс для внешнего ключа таблицы БД|создавать индексы на Foreign Key]], чтобы различные проверки БД выполнялись с использованием индекса.
Добавляем индекс на FK и проверяем результат:
![600](../../meta/files/images/Pasted%20image%2020240331093524.png)
Время выполнения было 281 ms, а стало 0.1 ms!
Большинство разработчиков на этом этапе успокоится, но можно ли сделать лучше?
#### Смотрим статистику
- [Таблица статистик pg_stats](../../dev/database/postgresql/Таблица%20статистик%20pg_stats.md)
![600](../../meta/files/images/Снимок%20экрана%202024-03-31%20в%2009.36.56.png)
В данном случае у нас 92% значений в колонке это null значения.
При большом значении `null_frac` нас уже меньше волнуют остальные параметры. Основываясь на этой информации мы можем уменьшить размер индекса. Для этого изменим запрос на создание индекса, добавив `where fk_id is not null`.
![600](../../meta/files/images/Pasted%20image%2020240331094502.png)
Это не ускорит нам запрос, но таким образом у нас получилось сжать индекс в 14 раз:
![500](../../meta/files/images/Pasted%20image%2020240331095259.png)
### Поиск записей по статусу
Возьмем типичную табличку, в которой есть какие-то статусы мы хотим находить данные по этому статусу.
![300](../../meta/files/images/Pasted%20image%2020240331095959.png)
![600](../../meta/files/images/Pasted%20image%2020240331100144.png)
Часто появляется желание сделать индекс по полю статуса:
![600](../../meta/files/images/Снимок%20экрана%202024-03-31%20в%2010.07.02.png)
Но по факту мы индексируем поле, которое имеет небольшую [селективность](../../dev/database/Селективность%20колонки.md). Такой индекс не эффективный.
Хороший вариант в данном случае:
![600](../../meta/files/images/Снимок%20экрана%202024-03-31%20в%2010.13.39.png)
Почти идеальный:
![600](../../meta/files/images/Снимок%20экрана%202024-03-31%20в%2010.15.06.png)
![500](../../meta/files/images/Pasted%20image%2020240331101612.png)
Идеальный. Совмещаем и [[../../dev/database/postgresql/Составной индекс в PostgreSQL|составной индекс]] и [[../../dev/database/postgresql/Частичный индекс|Частичный индекс]]
![[../../meta/files/images/Pasted image 20241021225124.png]]
### Онлайн статистика
Представим, что у вас небольшой продукт и PostgreSQL у вас единственное хранилище данных. И у вас есть задача показывать какую-то аналитику. Обычно для аналитических запросов хорошо использовать колоночные БД. Но так как ресурсов проекта у вас не много и задач на анализ не так много, то позволить себе такое вы не можете.
Можно сделать небольшой шаг в сторону колоночных БД в PostgreSQL за счет индексов.
В данном случае будем показывать сколько фруктов продано. Если использовать в лоб операции coun и sum, то они будут занимать достаточно много времени.
![[../../meta/files/images/Pasted image 20241021225909.png]]
Если не используем индексы
![[../../meta/files/images/Pasted image 20241021230132.png]]
Лучшее решение здесь это расчитывать заранее агрегирующие результаты за старые данные и обновлять их раз в сутки, а наиболее актуальные (за последние сутки) расчитывать отдельно и приплюсовывать к историческим.
Попробуем придумать индекс. Посмотрим на статистику по полю item. Видим, что больше половины таблицы занимает значение "дыня", значит с дыней придется прочитать половину таблицы.
![[../../meta/files/images/Pasted image 20241022212435.png]]
Поэтому первым стоит указать поле `created_at`, учитывая что оно участвует в запросе, а вторым полем добавить `item`.
![[../../meta/files/images/Pasted image 20241022212658.png]]
Но можно пойти еще дальше и использовать include(amount). Таким образом мы присоединим поле к индексу, оно не будет индексироваться. То есть значение amount будет лежать рядом, не нужно будет доставать значение из таблицы. Также используем where, чтобы отрезать все ненужные колонки.
![[../../meta/files/images/Pasted image 20241022213322.png]]
## Ответы на вопросы
- Автор в незнакомых базах смотрит
- на соотношение размеров таблицы и индексов.
- на количество чтений индексов
- дальше уже смотрит на то как были созданы индексы