vault backup: 2024-06-17 18:42:04

This commit is contained in:
Struchkov Mark 2024-06-17 18:42:04 +03:00
parent 675dc36dc0
commit 99966062c4
No known key found for this signature in database
GPG Key ID: A3F0AC3F0FA52F3C
55 changed files with 1054 additions and 301 deletions

33
.obsidian/graph.json vendored
View File

@ -6,7 +6,36 @@
"hideUnresolved": false,
"showOrphans": true,
"collapse-color-groups": true,
"colorGroups": [],
"colorGroups": [
{
"query": "path:wiki/zero ",
"color": {
"a": 1,
"rgb": 13730816
}
},
{
"query": "path:knowledge/dev ",
"color": {
"a": 1,
"rgb": 9582847
}
},
{
"query": "path:knowledge/health ",
"color": {
"a": 1,
"rgb": 8767232
}
},
{
"query": "path:",
"color": {
"a": 1,
"rgb": 5431378
}
}
],
"collapse-display": true,
"showArrow": false,
"textFadeMultiplier": 0,
@ -17,6 +46,6 @@
"repelStrength": 10,
"linkStrength": 1,
"linkDistance": 250,
"scale": 0.2539867059356025,
"scale": 0.26588896145134355,
"close": false
}

View File

@ -374,13 +374,5 @@
],
"key": "]"
}
],
"app:delete-file": [
{
"modifiers": [
"Mod"
],
"key": "Backspace"
}
]
}

View File

@ -24,24 +24,24 @@
"unresolvedLinks": false,
"recentFilesStore": [
{
"filepath": "Home.md",
"timestamp": 1718301876022
"filepath": "_inbox/Кэширование.md",
"timestamp": 1718638803720
},
{
"filepath": "knowledge/dev/Git.md",
"timestamp": 1718300752762
"filepath": "wiki/zero/00 HighLoad.md",
"timestamp": 1718638801082
},
{
"filepath": "knowledge/dev/Скрипты для Git.md",
"timestamp": 1718300748508
"filepath": "knowledge/human/Стресс.md",
"timestamp": 1718638580710
},
{
"filepath": "wiki/people/Алекс Корб.md",
"timestamp": 1718300621374
"filepath": "_inbox/Репликация в MySQL.md",
"timestamp": 1718638377453
},
{
"filepath": "wiki/Полис ОМС.md",
"timestamp": 1718300607145
"filepath": "_inbox/Репликация master-master.md",
"timestamp": 1718638184942
}
],
"starredFileStore": [],

View File

@ -1,7 +1,7 @@
{
"commitMessage": "vault backup: {{date}}",
"commitDateFormat": "YYYY-MM-DD HH:mm:ss",
"autoSaveInterval": 0,
"autoSaveInterval": 5,
"autoPushInterval": 0,
"autoPullInterval": 0,
"autoPullOnBoot": false,
@ -18,12 +18,12 @@
"treeStructure": false,
"refreshSourceControl": true,
"basePath": "",
"differentIntervalCommitAndPush": false,
"differentIntervalCommitAndPush": true,
"changedFilesInStatusBar": false,
"showedMobileNotice": true,
"refreshSourceControlTimer": 7000,
"showBranchStatusBar": true,
"setLastSaveToLastCommit": false,
"setLastSaveToLastCommit": true,
"submoduleRecurseCheckout": false,
"gitDir": "/Users/struchkov/Documents/Backup/obsidian_sadtech",
"showFileMenu": true,

View File

@ -1,9 +1,197 @@
{
"recentFiles": [
{
"basename": "Кэширование",
"path": "_inbox/Кэширование.md"
},
{
"basename": "00 HighLoad",
"path": "wiki/zero/00 HighLoad.md"
},
{
"basename": "Стресс",
"path": "knowledge/human/Стресс.md"
},
{
"basename": "Репликация в MySQL",
"path": "_inbox/Репликация в MySQL.md"
},
{
"basename": "Репликация master-master",
"path": "_inbox/Репликация master-master.md"
},
{
"basename": "CAP теорема",
"path": "_inbox/CAP теорема.md"
},
{
"basename": "Репликация master-slave",
"path": "_inbox/Репликация master-slave.md"
},
{
"basename": "Олег Чирухин",
"path": "wiki/people/Олег Чирухин.md"
},
{
"basename": "Home",
"path": "Home.md"
},
{
"basename": "Disaster recovery",
"path": "_inbox/Disaster recovery.md"
},
{
"basename": "Репликация БД",
"path": "_inbox/Репликация БД.md"
},
{
"basename": "Журнал БД",
"path": "_inbox/Журнал БД.md"
},
{
"basename": "Reliability",
"path": "_inbox/Reliability.md"
},
{
"basename": "High Availability",
"path": "_inbox/High Availability.md"
},
{
"basename": "Репликация",
"path": "_inbox/Репликация.md"
},
{
"basename": "Шардирование",
"path": "_inbox/Шардирование.md"
},
{
"basename": "Настройка репликации в PostgreSQL",
"path": "_inbox/Настройка репликации в PostgreSQL.md"
},
{
"basename": "Репликация в PostgreSQL",
"path": "_inbox/Репликация в PostgreSQL.md"
},
{
"basename": "Оптимизация SQL запросов",
"path": "_inbox/Оптимизация SQL запросов.md"
},
{
"basename": "JOIN SQL",
"path": "_inbox/JOIN SQL.md"
},
{
"basename": "Индекс в PostgreSQL",
"path": "_inbox/Индекс в PostgreSQL.md"
},
{
"basename": "Составные индексы в PostgreSQL",
"path": "_inbox/Составные индексы в PostgreSQL.md"
},
{
"basename": "00 PostgreSQL",
"path": "wiki/zero/00 PostgreSQL.md"
},
{
"basename": "PgBouncer",
"path": "_inbox/PgBouncer.md"
},
{
"basename": "IN SQL",
"path": "_inbox/IN SQL.md"
},
{
"basename": "00 SQL",
"path": "wiki/zero/00 SQL.md"
},
{
"basename": "Explain в PostgreSQL",
"path": "_inbox/Explain в PostgreSQL.md"
},
{
"basename": "Индексы в MySQL",
"path": "_inbox/Индексы в MySQL.md"
},
{
"basename": "Профилирование запросов в PostgreSQL",
"path": "knowledge/dev/database/Профилирование запросов в PostgreSQL.md"
},
{
"basename": "pg_stat_statements",
"path": "pg_stat_statements.md"
},
{
"basename": "Доклад. Индексы в PostgreSQL. Как понять, что создавать",
"path": "source/доклады/Доклад. Индексы в PostgreSQL. Как понять, что создавать.md"
},
{
"basename": "Обучающий курс от HighLoad конференции 2024",
"path": "source/курсы/_toc/Обучающий курс от HighLoad конференции 2024.md"
},
{
"basename": "Memcached",
"path": "_inbox/Memcached.md"
},
{
"basename": "00 Nginx",
"path": "wiki/zero/00 Nginx.md"
},
{
"basename": "Explain в MySQL",
"path": "_inbox/Explain в MySQL.md"
},
{
"basename": "Extended keys MySQL",
"path": "_inbox/Extended keys MySQL.md"
},
{
"basename": "ORDER BY",
"path": "knowledge/dev/database/ORDER BY.md"
},
{
"basename": "Архитектура MySQL",
"path": "Архитектура MySQL.md"
},
{
"basename": "Идеи для ремонта",
"path": "projects/Ремонт квартиры/Идеи для ремонта.md"
},
{
"basename": "Предлоги в Английском",
"path": "knowledge/english/Предлоги в Английском.md"
},
{
"basename": "Index condition pushdown",
"path": "_inbox/Index condition pushdown.md"
},
{
"basename": "Покрывающий индекс",
"path": "_inbox/Покрывающий индекс.md"
},
{
"basename": "Составные индексы в MySQL",
"path": "_inbox/Составные индексы в MySQL.md"
},
{
"basename": "Составные индексы в БД",
"path": "Составные индексы в БД.md"
},
{
"basename": "Без названия",
"path": "Без названия.md"
},
{
"basename": "00 MySQL",
"path": "wiki/zero/00 MySQL.md"
},
{
"basename": "00 Linux",
"path": "wiki/zero/00 Linux.md"
},
{
"basename": "Ударение",
"path": "_inbox/Ударение.md"
},
{
"basename": "Git",
"path": "knowledge/dev/Git.md"
@ -11,194 +199,6 @@
{
"basename": "Скрипты для Git",
"path": "knowledge/dev/Скрипты для Git.md"
},
{
"basename": "Алекс Корб",
"path": "wiki/people/Алекс Корб.md"
},
{
"basename": "Полис ОМС",
"path": "wiki/Полис ОМС.md"
},
{
"basename": "Не переработано",
"path": "source/Не переработано.md"
},
{
"basename": "Книга",
"path": "meta/templates/Книга.md"
},
{
"basename": "Личная продуктивность 1",
"path": "knowledge/productivity/Личная продуктивность 1.md"
},
{
"basename": "Ежегодная проверка здоровья",
"path": "checklists/Ежегодная проверка здоровья.md"
},
{
"basename": "Киники",
"path": "_inbox/Киники.md"
},
{
"basename": "Заявление на АГС",
"path": "archive/Мобилизация/Заявление на АГС.md"
},
{
"basename": "Изучаю gRPC",
"path": "source/доклады/Изучаю gRPC.md"
},
{
"basename": "Про поветски",
"path": "archive/Мобилизация/Про поветски.md"
},
{
"basename": "containerd.io",
"path": "_inbox/containerd.io.md"
},
{
"basename": "Simple",
"path": "knowledge/english/Simple.md"
},
{
"basename": "Разработка",
"path": "knowledge/dev/Разработка.md"
},
{
"basename": "Дополнительные материалы по Java",
"path": "source/доклады/Дополнительные материалы по Java.md"
},
{
"basename": "JOIN",
"path": "knowledge/dev/database/JOIN.md"
},
{
"basename": "Docker compose для запуска socks5",
"path": "knowledge/dev/Docker compose для запуска socks5.md"
},
{
"basename": "Полезное про собеседования",
"path": "notes/Полезное про собеседования.md"
},
{
"basename": "Сезонные фрукты и овощи",
"path": "wiki/Сезонные фрукты и овощи.md"
},
{
"basename": "Заметки по ТЗ 4",
"path": "archive/Я.Практикум/Полезное/Заметки по ТЗ 4.md"
},
{
"basename": "ConcurrentModificationException",
"path": "archive/Я.Практикум/Полезное/ConcurrentModificationException.md"
},
{
"basename": "Ежедневный чеклист",
"path": "checklists/Ежедневный чеклист.md"
},
{
"basename": "Использование нескольких репозиториев в проекте",
"path": "archive/Я.Практикум/Полезное/Использование нескольких репозиториев в проекте.md"
},
{
"basename": "Тимлид",
"path": "_inbox/Тимлид.md"
},
{
"basename": "Работа с архитектурой информационных систем в нашем изменчивом мире",
"path": "source/доклады/Работа с архитектурой информационных систем в нашем изменчивом мире.md"
},
{
"basename": "Looking Glass",
"path": "knowledge/dev/network/Looking Glass.md"
},
{
"basename": "Open System Interconnection Reference Model",
"path": "knowledge/dev/network/Open System Interconnection Reference Model.md"
},
{
"basename": "Нелинейная зависимость длительности от сложности задачи",
"path": "source/цитаты/Нелинейная зависимость длительности от сложности задачи.md"
},
{
"basename": "Mock конфигурация для Oauth2 SpringBoot",
"path": "knowledge/dev/java/frameworks/spring/Mock конфигурация для Oauth2 SpringBoot.md"
},
{
"basename": "Second Brain",
"path": "knowledge/education/Second Brain.md"
},
{
"basename": "Рекомендации к ТЗ 6",
"path": "archive/Я.Практикум/Полезное/Рекомендации к ТЗ 6.md"
},
{
"basename": "Ешки",
"path": "knowledge/health/питание/Ешки.md"
},
{
"basename": "At или in?",
"path": "knowledge/english/At или in?.md"
},
{
"basename": "Создание linux сервиса для приложения Spring Boot",
"path": "knowledge/dev/java/snippets/Создание linux сервиса для приложения Spring Boot.md"
},
{
"basename": "SponsorBlock",
"path": "_inbox/SponsorBlock.md"
},
{
"basename": "Мультимодульные проекты c Jandex",
"path": "knowledge/dev/Мультимодульные проекты c Jandex.md"
},
{
"basename": "excalibrain",
"path": "excalibrain.md"
},
{
"basename": "image (2)",
"path": "meta/files/image (2).png"
},
{
"basename": "2024-03-10 1710054825",
"path": "_inbox/2024-03-10 1710054825.md"
},
{
"basename": "Майнд-мэп",
"path": "knowledge/productivity/Майнд-мэп.md"
},
{
"basename": "Как оценить уровень финансовой свободы?",
"path": "knowledge/economy/Как оценить уровень финансовой свободы?.md"
},
{
"basename": "Сериализация и Десериализация даты в Jackson",
"path": "knowledge/dev/java/snippets/Сериализация и Десериализация даты в Jackson.md"
},
{
"basename": "Задача 24",
"path": "notes/Собеседования/Задачи/Задача 24.md"
},
{
"basename": "Семейная ипотека 6%",
"path": "archive/Квартира/Семейная ипотека 6%.md"
},
{
"basename": "Проект",
"path": "knowledge/productivity/Проект.md"
},
{
"basename": "Циклические зависимости сервисов",
"path": "knowledge/dev/java/other/Циклические зависимости сервисов.md"
},
{
"basename": "Приветственное сообщение",
"path": "archive/Я.Практикум/Сообщения/Приветственное сообщение.md"
},
{
"basename": "Настройки noteshare для Obsidian",
"path": "notes/Настройки noteshare для Obsidian.md"
}
],
"omittedPaths": [],

View File

@ -16,4 +16,5 @@ SELECT * FROM posts WHERE author = "Peter"
JOIN comments ON posts. id = comments.post_id
```
Индекс по `posts.id` бесполезен. Индекс по `comments.post_id` обязателен.
Индекс по `posts.id` бесполезен. Индекс по `comments.post_id` обязателен.

View File

@ -16,4 +16,4 @@ CAP теорема — это принцип, описывающий фунда
Согласно теореме CAP, в любой момент времени система может обеспечивать только два из этих трёх свойств. Это означает, что при разработке системы приходится принимать компромисс между этими свойствами в зависимости от требований приложения и условий эксплуатации. Например, если для системы критически важна согласованность данных и её устойчивость к разделению, возможно придётся пожертвовать её доступностью в некоторых сценариях.
Google заявляет, что их продукт Spanner якобы нарушает CAP теорему.
Google заявляет, что их продукт Google Spanner якобы нарушает CAP теорему.

View File

@ -1,14 +1,15 @@
---
aliases:
aliases:
- DR
tags:
- зрелость/🌱
date:
- - 2024-03-05
zero-link:
- "[[00 HighLoad]]"
parents: []
parents:
linked:
---
Восстановление после катастрофы.
Восстановление после сбоев.
Потеря данных почти всегда
Почти всегда происходит потеря данных.

View File

@ -0,0 +1,32 @@
---
aliases:
tags:
- зрелость/🌱
date:
- - 2024-06-16
zero-link:
- "[[00 MySQL]]"
parents:
linked:
- "[[Explain в PostgreSQL]]"
---
![](Архитектура%20MySQL.md#^432879)
**Недостатки explain**. Многие связаны с работой оптимизатора.
- Не учитывает хранимые функции
- Может обмануть. И выполнение запроса будет отличаться от плана.
- Мало информации: план совпадает, производительность нет. Одинаковые результаты для различных ситуаций
- Выполнение from подзапросов
- Может выполняться дольше, чем сам запрос
Пример выполнения
![](Pasted%20image%2020240616122716.png)
Нужно обратить внимание на
- type: ALL. Значит индексы не используются
- type: eq_ref. Поиск по ключу
- key. Это индекс, который был выбран.
- key_len. Длина индекса, которая была использована в [составном](Составные%20индексы%20в%20MySQL.md)
## Дополнительные материалы
- [Основы индексирования и возможности EXPLAIN в MySQL](https://highload.guide/blog/basics_indexing.html)

View File

@ -0,0 +1,48 @@
---
aliases:
tags:
- зрелость/🌱
date:
- - 2024-06-10
zero-link:
- "[[00 PostgreSQL]]"
parents:
- "[[Профилирование запросов в PostgreSQL]]"
linked:
- "[[Explain в MySQL]]"
---
Используя ключевое слово `EXPLAIN` перед запросом, можно получить детальную информацию о том, что **планирует** сделать 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 не выполняет запрос, поэтому результаты будут лишь приблизительными. Можно улучшить качество анализа, если добавить ключевое слово `explain analyze`, тогда explain также выполнит запрос.
PostgreSQL использует условные единицы обозначающие стоимость выполнения запроса - cost. Один cost это время, которое затрачивается на извлечение 1 блока размером 8 килобайт при Seq Scan. При этом обычно используется 2 значения. Первое означает сколько времени пройдет до начала первых результатов, а вторая когда вернется весь результат.
Если cost очень маленький, а actual time большое, это может означать, что есть проблемы со сбором статистики. Возможно выключен автовакуум?
Стоит найти самый дорогой узел запроса и оптимизировать его.
**Виды проходов по индексу:**
- Seq Scan - последовательный просмотр таблицы. Худший вариант.
- Index Scan - просмотр по индексу в таблице
- Index Only Scan - был использован [Покрывающий индекс](Покрывающий%20индекс.md)
- Bitmap Heap Scan - оптимизация с построением битовых карт для поиска. Сначала строятся битовые карты с использованием нескольких индексов, затем эти битовые карты комбинируются.
## Дополнительные материалы
- [Производительность запросов в PostgreSQL / Илья Космодемьянский (PostgreSQL Consulting) - YouTube](https://www.youtube.com/watch?v=c-ySk8COI1c)

View File

@ -1,37 +0,0 @@
---
aliases:
tags:
- зрелость/🌱
date:
- - 2024-06-10
zero-link:
- "[[00 PostgreSQL]]"
parents:
- "[[Профилирование запросов в PostgreSQL]]"
linked:
---
Используя ключевое слово `EXPLAIN` перед запросом, можно получить детальную информацию о том, что делает PostgreSQL под капотом для выполнения запроса, и что это ему стоит.
Пример выполнения
```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;
```
Explain не выполняет запрос, поэтому результаты будут лишь приблизительными. Можно улучшить качество анализа, если добавить ключевое слово `explain analyze`, тогда explain также выполнит запрос.
**Виды проходов по индексу:**
- Seq Scan - последовательный просмотр таблицы. Худший вариант.
- Index Scan - просмотр по индексу в таблице
- Index Only Scan - был использован [Покрывающий индекс](Покрывающий%20индекс.md)
- Bitmap Heap Scan - оптимизация с построением битовых карт для поиска. Сначала строятся битовые карты с использованием нескольких индексов, затем эти битовые карты комбинируются.

View File

@ -0,0 +1,16 @@
---
aliases:
tags:
- зрелость/🌱
date:
- - 2024-06-16
zero-link:
- "[[00 MySQL]]"
parents:
- "[[Индексы в MySQL]]"
linked:
---
В MySQL термин "extended keys" относится к расширению использования индексов, введённому в MySQL 5.6, которое улучшает оптимизацию запросов. Расширенные ключи (extended keys) позволяют оптимизатору учитывать все колонки, используемые в запросе (в SELECT, WHERE, ORDER BY, GROUP BY и других частях запроса), для определения того, какой индекс будет наиболее эффективным для выполнения запроса.
Особенность ключей в InnoDB это то, что вторичные ключи ссылаются на первичный ключ, поэтому фактически вторичный ключ в InnoDB представляет собой вторичный ключ + указатель на первичный ключ. Используется только для фильтрации строк.
![](Pasted%20image%2020240616114457.png)

View File

@ -11,20 +11,22 @@ zero-link:
parents:
linked:
---
High Availability (Высокая доступность). Отношение времени, когда сайт работал к общему времени. Исторически измеряется в 9-ках.
High Availability (Высокая доступность). От ношение времени, когда сервис работал к общему времени.
Исторически измеряется в 9-ках.
| Доступность | Время простоя в год | Время простоя в месяц |
| ---- | ---- | :--: |
| 99% | 3.65 дней | 7.20 часов |
| 99,5% | 1.83 дней | 3.60 часов |
| 99,9% | 8.76 часов | 43.2 минут |
| 99,95% | 4.38 часов | 21.56 минут |
| 99,99% | 52.56 минут | 4.32 минут |
| 99,99% | 5.26 минут | 25.9 секунд |
| 99,9999% | 31.5 секунд | 2.59 секунд |
| ----------- | ------------------- | :-------------------: |
| 99% | 3.65 дней | 7.20 часов |
| 99,5% | 1.83 дней | 3.60 часов |
| 99,9% | 8.76 часов | 43.2 минут |
| 99,95% | 4.38 часов | 21.56 минут |
| 99,99% | 52.56 минут | 4.32 минут |
| 99,999% | 5.26 минут | 25.9 секунд |
| 99,9999% | 31.5 секунд | 2.59 секунд |
Что влияет на доступность?
- Отказы и аварии. Чаще всего незапланированные. Техногенного или природного характера.
- Отказы и аварии. Чаще всего не запланированные. Техногенного или природного характера.
- Запланированные. Обновление ПО, которое невозможно выполнить без остановки.
- [Reliability](Reliability.md)
## Вопросы

14
_inbox/IN SQL.md Normal file
View File

@ -0,0 +1,14 @@
---
aliases:
tags:
- зрелость/🌱
date:
- - 2024-06-17
zero-link:
- "[[00 SQL]]"
parents:
linked:
---
## Проблемы производительности IN
Длинный IN, который очень часто генерируют ORM. [Исправление](Pasted%20image%2020240617132439.png)
![500](Pasted%20image%2020240617132203.png)

View File

@ -0,0 +1,16 @@
---
aliases:
tags:
- зрелость/🌱
date:
- - 2024-06-16
zero-link:
- "[[00 MySQL]]"
parents:
linked:
---
Мало что понял
![](Pasted%20image%2020240616113900.png)
- [Основы индексирования и расширенные возможности EXPLAIN в MySQL / Василий Лукьянчиков (Станигост) - YouTube](https://youtu.be/DFmdW5UwhjA?si=_cXgbvaVI5KUP2fv&t=1198)

29
_inbox/JOIN SQL.md Normal file
View File

@ -0,0 +1,29 @@
---
aliases:
tags:
- зрелость/🌱
date: 2024-02-05
zero-link:
- "[[00 SQL]]"
parents:
linked:
---
Postgres имеет три основных алгоритма Join'а, а именно
- Nested Loop. Берем данные из одной таблицы и циклами их Join'им
- Hash index. Одна, чаще маленькая, таблица хэшируется и по этому хэшу Join'ится с другой таблицей
- Merge Join.
```sql
SELECT * FROM posts WHERE author = "Peter"
JOIN comments ON posts. id = comments.post_id
```
Индекс по `posts.id` бесполезен. Индекс по `comments.post_id` обязателен. Если вы создадите индекс, оптимизатор выберет Nested Loop, и все будет работать быстро.
## Почему JOIN работает медленно?
- Индекс для полей по которым джойним добавлен?
## Заметки
- B MySQL используется метод nested loops, но с оптимизациями.
- У вас оптимизатор из каких-то соображений выбирает Nested Loop, а вам кажется, что одна таблица очень маленькая, другая очень большая и Hash Join там был бы очень уместен, потому что маленькую таблицу можно быстро прохэшировать и быстро с ней работать. Посмотрите, сколько у вас work mem'а. т.е. сколько памяти может занять один worker Postgresа. Если эта таблица хэшируется в, например, 100 Мб, а у вас work mem'а выдано только 30 Мб, то worker будет работать медленно. Если вы добавите work mem'а и хэширование начнет вмещаться в память, оптимизатор выберет правильный Hash Join и будет быстро и хорошо.

View File

@ -41,3 +41,5 @@ Memcached не является надежным хранилищем воз
Для распределения нагрузки и достижения отказоустойчивости вместо одного сервера memcached используется кластер из таких серверов. Сервера, входящие в кластер, могут быть сконфигурированы с различным объемом памяти, при этом общий объем кэша будет равен сумме объемов кэшей всех memcached, входящих в кластер. Процесс memcached может быть запущен на сервере, где слабо используется процессор и не загружена до предела сеть (например, на файловом сервере). При высокой нагрузке на процессор memcached может не успевать достаточно быстро отвечать на запросы, что приводит к деградации сервиса.
При работе с кластером ключи распределяются по серверам, то есть каждый сервер обрабатывает часть общего массива ключей проекта. Отказоустойчивость следует из того факта, что в случае отказа одного из серверов ключи будут перераспределены по оставшимся серверам кластера. При этом, конечно же, содержимое отказавшего сервера будет потеряно (см. раздел «Потеря ключей»). Вслучае необходимости важные ключи можно хранить не на одном сервере, а дублировать на нескольких, так можно минимизировать последствия падения сервера за счет избыточности хранения.
## Дополнительные материалы
- [Web, кэширование и memcached](https://highload.guide/blog/web-caching-memcached.html)

View File

@ -7,12 +7,18 @@ date:
- - 2024-02-26
zero-link:
- "[[00 HighLoad]]"
parents: []
parents:
linked:
- "[[High Availability]]"
---
Это метод повышения [High Availability](High%20Availability.md). Обеспечивается техническими и организационными средствами.
Техническое средство - избыточность:
- сервисов
- active-passive. Это когда запасной сервис заранее поднят, но не используется.
- данных
- параллельные кластеры.
- данных
- [Репликация](source/курсы/otus/Архитектор%20высоких%20нагрузок%202019/Репликация.md)
Организационные средства:
- Дежурства разработчиков и DevOps

View File

@ -24,11 +24,12 @@ linked:
- Усложненное технического обслуживание. Индексы пухнут и переодически их нужно пересоздавать
**Когда индексы не нужны?**
- Малая [Селективность колонки](Селективность%20колонки.md)
- Накладные расходы на поддержание индекса больше пользы
- Малая [Селективность колонки](Селективность%20колонки.md).
- Большие накладные расходы на поддержание индекса.
- Когда индекс не используется вовсе.
**Когда индексы не работают?**
- В условии используется вычисляемое выражение: `WHERE counter + 1 = 46`
- Если будет отобрано слишком много записей.
- Из агрегирующих функций только `min()` и `max()` получат ускорение.
- Индексы хорошо работают с логическим И, и плохо работают с логическим ИЛИ.
@ -78,7 +79,7 @@ linked:
- Собрать статистику нагрузки на БД от запросов.
- Представление [pg_stats](Таблица%20статистик%20pg_stats.md).
- Инструменты для сбора статистики:
- pg_stat_statements - отличный инструмент
- [pg_stat_statements](pg_stat_statements.md) - отличный инструмент
- pgBadger - использовать с осторожностью. Собирает статистику из логов postgres. Но в логи попадают не все запросы.
- Иметь примеры запросов с параметрами.
- Для понимания входящих параметров запроса.
@ -89,7 +90,7 @@ linked:
При создании индекса важно учитывать [селективность колонки](Селективность%20колонки.md) (разнообразие значений), чем она выше, тем лучше индекс будет выполнять свою задачу.
![](Составные%20индексы%20в%20PostgreSQL.md#^630c7e)
![](Составные%20индексы%20в%20БД.md#^630c7e)
- [PostgreSQL: Documentation: 16: CREATE INDEX](https://www.postgresql.org/docs/current/sql-createindex.html)

View File

@ -0,0 +1,33 @@
---
aliases:
tags:
- зрелость/🌱
date:
- - 2024-06-16
zero-link:
- "[[00 MySQL]]"
parents:
linked:
---
![Архитектура](Архитектура%20MySQL.md#^42f122)
Индексы реализуются на уровне движка хранилища, они не стандартизованы. Каждый движок может предоставлять свою реализацию одного и того же индекса. Например, B-Tree индекс в MyISAM хранит указатель на сами данные, а в InnoDB он хранит указатель на первичный ключ; в MyISAM происходит сжатие префиксных индексов, а в InnoDB этого не происходит, но зато там есть кэширование и данных, и индексов.
> [!WARNING] Дублирование индексов
> MySQL никак не управляет дублированием индексов. Например, если создать таблицу с PK, а потом создать на PK индекс и UNIQUE(PK), то мы получим не один, а 3 одинаковых индекса.
Если у нас есть index(A) и index(A,B), то index(A) будет лишним, потому что в случае index(A,B) часть А может использоваться в нем. (если оба [B-tree](B-tree.md))
Используются [покрывающие индексы](Покрывающий%20индекс.md)
[Extended keys MySQL](Extended%20keys%20MySQL.md)
**Когда индексы не работают?**
- Часть выражения: id + 1 = 3.
- Когда есть преобразование типов: key_str = 15
- Несоответсвие кодировок
- Не используется левая часть [составного индекса](Составные%20индексы%20в%20MySQL.md): index(a,b); where b = 5;
- Поиск по суффиксу: '%x'
- Сравнение с исходной таблицей: t.key = t.col
Например, A in (0,1) и А between 0 and 1 это эквивалентные формы, это диапазон и там, и там, но в случае, когда это A in (0,1) список, он понимает, что это не диапазон, а заменяет на множественное условие равенства. В этом случае он будет использовать индекс. Это еще один нюанс MySQL, т.е. нужно смотреть, как писать либо списком, либо ставить <> . Он это различает.

View File

@ -14,7 +14,7 @@ linked:
Ускорить сложные запросы может кэширование: мы помещаем результат вычислений в некоторое хранилище (например, [Memcached](Memcached.md) или [Redis](Redis.md)), которое обладает отличными характеристиками по времени доступа к информации. Теперь вместо обращений к медленным, сложным и тяжелым backendам нам достаточно выполнить запрос к быстрому кэшу.
Системы используемые для кэширования обычно не являются надежными, так что не следует хранить только там какие-то важные данные. Данные можно разделить на несколько категорий:
==Системы используемые для кэширования обычно не являются надежными, так что не следует хранить только там какие-то важные данные.== Данные можно разделить на несколько категорий:
- «**Можно потерять**». К этой категории относятся кэши выборок из базы данных. Потеря таких ключей не так страшна, потому что мы можем легко восстановить их значения, обратившись заново к backendу. Однако частые потери кэшей приводят к излишним обращениям к БД.
- «**Не хотелось бы потерять**». Здесь можно упомянуть счетчики посетителей сайта, просмотров ресурсов и т.п. Хоть и восстановить эти значения иногда напрямую невозможно, но значения этих ключей имеют ограниченный по времени смысл: через несколько минут их значение уже неактуально, и будет рассчитано заново.
- «**Совсем не должны терять**». Кэш удобен для хранения сессий пользователей. Однако содержимое сессий не хотелось бы терять никогда иначе пользователей на сайте будет «разлогинивать». Как попытаться избежать? Можно кластеризовать систему кэширования, так вероятность потери снижается.

View File

@ -0,0 +1,344 @@
---
aliases:
tags:
- зрелость/🌱
date:
- - 2024-06-17
zero-link:
- "[[00 PostgreSQL]]"
parents:
- "[[Репликация в PostgreSQL]]"
linked:
---
## Физическая репликация
1. Создаем сеть, запоминаем адрес
```shell
docker network create pgnet
docker network inspect pgnet | grep Subnet # Запомнить маску сети
```
2. Поднимаем мастер
```shell
docker run -dit -v "$PWD/volumes/pgmaster/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "5432:5432" --restart=unless-stopped --network=pgnet --name=pgmaster postgres
```
3. Меняем postgresql.conf на мастере
```conf
ssl = off
wal_level = replica
max_wal_senders = 4 # expected slave num
```
4. Подключаемся к мастеру и создаем пользователя для репликации
```shell
docker exec -it pgmaster su - postgres -c psql
create role replicator with login replication password 'pass';
exit
```
5. Добавляем запись в `pgmaster/pg_hba.conf` с `subnet` с первого шага
```
host replication replicator __SUBNET__ md5
```
6. Перезапустим мастер
```shell
docker restart pgmaster
```
7. Сделаем бэкап для реплик
```shell
docker exec -it pgmaster bash
mkdir /pgslave
pg_basebackup -h pgmaster -D /pgslave -U replicator -v -P --wal-method=stream
exit
```
8. Копируем директорию себе
```shell
docker cp pgmaster:/pgslave volumes/pgslave/
```
9. Создадим файл, чтобы реплика узнала, что она реплика
```shell
touch volumes/pgslave/standby.signal
```
10. Меняем `postgresql.conf` на реплике `pgslave`
```conf
primary_conninfo = 'host=pgmaster port=5432 user=replicator password=pass application_name=pgslave'
```
11. Запускаем реплику `pgslave`
```shell
docker run -dit -v "$PWD/volumes/pgslave/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "15432:5432" --network=pgnet --restart=unless-stopped --name=pgslave postgres
```
12. Запустим вторую реплику `pgasyncslave`
- скопируем бэкап
```shell
docker cp pgmaster:/pgslave volumes/pgasyncslave/
```
- изменим настройки `pgasyncslave/postgresql.conf`
```conf
primary_conninfo = 'host=pgmaster port=5432 user=replicator password=pass application_name=pgasyncslave'
```
- дадим знать что это реплика
```shell
touch volumes/pgasyncslave/standby.signal
```
- запустим реплику `pgasyncslave`
```shell
docker run -dit -v "$PWD/volumes/pgasyncslave/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "25432:5432" --network=pgnet --restart=unless-stopped --name=pgasyncslave postgres
```
14. Убеждаемся что обе реплики работают в асинхронном режиме на `pgmaster`
```shell
docker exec -it pgmaster su - postgres -c psql
select application_name, sync_state from pg_stat_replication;
exit;
```
15. Включаем синхронную репликацию на `pgmaster`
- меняем файл `pgmaster/postgresql.conf`
```conf
synchronous_commit = on
synchronous_standby_names = 'FIRST 1 (pgslave, pgasyncslave)'
```
- перечитываем конфиг
```shell
docker exec -it pgmaster su - postgres -c psql
select pg_reload_conf();
exit;
```
16. Убеждаемся, что реплика стала синхронной
```shell
docker exec -it pgmaster su - postgres -c psql
select application_name, sync_state from pg_stat_replication;
exit;
```
17. Создадим тестовую таблицу на `pgmaster` и проверим репликацию
```shell
docker exec -it pgmaster su - postgres -c psql
create table test(id bigint primary key not null);
insert into test(id) values(1);
select * from test;
exit;
```
18. Проверим наличие данных на `pgslave`
```shell
docker exec -it pgslave su - postgres -c psql
select * from test;
exit;
```
19. Проверим наличие данных на `pgasyncslave`
```shell
docker exec -it pgasyncslave su - postgres -c psql
select * from test;
exit;
```
20. Попробуем сделать `insert` на `pgslave`
```shell
docker exec -it pgslave su - postgres -c psql
insert into test(id) values(2);
exit;
```
21. Укладываем репилку `pgasyncslave` и проверяем работу `pgmaster` и `pgslave`
```shell
docker stop pgasyncslave
docker exec -it pgmaster su - postgres -c psql
select application_name, sync_state from pg_stat_replication;
insert into test(id) values(2);
select * from test;
exit;
docker exec -it pgslave su - postgres -c psql
select * from test;
exit;
```
22. Укладываем репилку `pgslave` и проверяем работу `pgmaster`, а потом возвращаем реплику `pgslave`
- terminal 1
```shell
docker stop pgslave
docker exec -it pgmaster su - postgres -c psql
select application_name, sync_state from pg_stat_replication;
insert into test(id) values(3);
exit;
```
- terminal 2
```shell
docker start pgslave
```
23. Возвращаем вторую реплику `pgasyncslave`
```shell
docker start pgasyncslave
```
24. Убиваем мастер `pgmaster`
```shell
docker stop pgmaster
```
25. Запромоутим реплику `pgslave`
```shell
docker exec -it pgslave su - postgres -c psql
select pg_promote();
exit;
```
26. Пробуем записать в новый мастер `pgslave`
```shell
docker exec -it pgslave su - postgres -c psql
insert into test(id) values(4);
exit;
```
27. Настраиваем репликацию на `pgslave` (`pgslave/postgresql.conf`)
- изменяем конфиг
```conf
synchronous_commit = on
synchronous_standby_names = 'ANY 1 (pgmaster, pgasyncslave)'
```
- перечитываем конфиг
```shell
docker exec -it pgslave su - postgres -c psql
select pg_reload_conf();
exit;
```
28. Подключим вторую реплику `pgasyncslave` к новому мастеру `pgslave`
- изменяем конфиг `pgasyncslave/postgresql.conf`
```conf
primary_conninfo = 'host=pgslave port=5432 user=replicator password=pass application_name=pgasyncslave'
```
- перечитываем конфиг
```shell
docker exec -it pgasyncslave su - postgres -c psql
select pg_reload_conf();
exit;
```
29. Проверяем что к новому мастеру `pgslave` подключена реплика и она работает
```shell
docker exec -it pgslave su - postgres -c psql
select application_name, sync_state from pg_stat_replication;
insert into test(id) values (5)
select * from test;
exit;
docker exec -it pgasyncslave su - postgres -c psql
select * from test;
exit;
```
30. Восстановим старый мастер `pgmaster` как реплику
1. Помечаем как реплику
```shell
touch volumes/pgmaster/standby.signal
```
2. Изменяем конфиг `pgmaster/postgresql.conf`
```conf
primary_conninfo = 'host=pgslave port=5432 user=replicator password=pass application_name=pgmaster'
```
3. Запустим `pgmaster`
```shell
docker start pgmaster
```
4. Убедимся что `pgmaster` подключился как реплика к `pgslave`
```shell
docker exec -it pgslave su - postgres -c psql
select application_name, sync_state from pg_stat_replication;
exit;
```
## Логическая репликация
1. Меняем `wal_level` для текущего мастера `pgslave`
1. Изменяем настройки `pgslave/postgresql.conf`
```conf
wal_level = logical
```
2. Перезапускаем `pgslave`
```shell
docker restart pgslave
```
2. Создадим публикацию в `pgslave`
```shell
docker exec -it pgslave su - postgres -c psql
GRANT CONNECT ON DATABASE postgres TO replicator;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO replicator;
create publication pg_pub for table test;
exit;
```
3. Создадим новый сервер `pgstandalone` для логической репликации
```shell
docker run -dit -v "$PWD/volumes/pgstandalone/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "35432:5432" --restart=unless-stopped --network=pgnet --name=pgstandalone postgres
```
4. Копируем файлы c `pgslave` в `pgstandalone` и восстанавливаем
```shell
docker exec -it pgslave su - postgres
pg_dumpall -U postgres -r -h pgslave -f /var/lib/postgresql/roles.dmp
pg_dump -U postgres -Fc -h pgslave -f /var/lib/postgresql/schema.dmp -s postgres
exit;
docker cp pgslave:/var/lib/postgresql/roles.dmp .
docker cp roles.dmp pgstandalone:/var/lib/postgresql/roles.dmp
docker cp pgslave:/var/lib/postgresql/schema.dmp .
docker cp schema.dmp pgstandalone:/var/lib/postgresql/schema.dmp
docker exec -it pgstandalone su - postgres
psql -f roles.dmp
pg_restore -d postgres -C schema.dmp
exit
```
5. Создаем подписку на `pgstandalone`
```shell
docker exec -it pgstandalone su - postgres -c psql
CREATE SUBSCRIPTION pg_sub CONNECTION 'host=pgslave port=5432 user=replicator password=pass dbname=postgres' PUBLICATION pg_pub;
exit;
```
6. Убеждаемся что репликация запущена
```shell
docker exec -it pgstandalone su - postgres -c psql
select * from test;
exit;
```
7. Сделаем конфликт в данных
1. Вставляем данные в подписчике `pgstandalone`
```shell
docker exec -it pgstandalone su - postgres -c psql
insert into test values(9);
exit;
```
2. Вставляем данные в паблишере `pgslave`
```shell
docker exec -it pgslave su - postgres -c psql
insert into test values(9);
insert into test values(10);
exit;
```
3. Убеждаемся что записи с id 10 не появилось на `pgstandalone`
```shell
docker exec -it pgstandalone su - postgres -c psql
select * from test;
exit;
```
4. Посмотрим в логи `pgstandalone` и убедимся что у нас произошел разрыв репликации
```shell
docker logs pgstandalone
```
```
2023-03-27 16:15:02.753 UTC [258] ERROR: duplicate key value violates unique constraint "test_pkey"
2023-03-27 16:15:02.753 UTC [258] DETAIL: Key (id)=(9) already exists.
2023-03-28 18:30:42.893 UTC [108] CONTEXT: processing remote data for replication origin "pg_16395" during message type "INSERT" for replication target relation "public.test" in transaction 739, finished at 0/3026450
```
8. Исправляем конфликт
```shell
docker exec -it pgstandalone su - postgres -c psql
SELECT pg_replication_origin_advance('pg_16395', '0/3026451'::pg_lsn); # message from log + 1
ALTER SUBSCRIPTION pg_sub ENABLE;
select * from test;
exit;
```

View File

@ -0,0 +1,53 @@
---
aliases:
tags:
- зрелость/🌱
date:
- - 2024-06-17
zero-link:
- "[[00 Базы Данных]]"
parents:
- "[[00 SQL]]"
linked:
---
Что такое плохой или медленный запрос
- Запрос по времени работает дольше остальных
- Запрос, который потребляет больше ресурсов, чем остальные запросы
- Быстро выполняемый запрос может быть также плохим, если выполняется часто и в сумме за N времени потребляет много ресурсов.
**Алгоритм оптимизации запросов:**
- Проверить настройки. Возможно проблемы не связаны с запросами?
- Слабое железо у сервера БД
- Проблемы сети
- Неправильные настройки БД
- [PostgreSQL](00%20PostgreSQL.md)
- Много конекшенов, но ее используется [PgBouncer](PgBouncer.md).
- Выключен или не настроен autovacuum
- Отобрать запросы для оптимизации
- ==Анализом необходимо заниматься только на продуктовой БД.==
- Все подряд оптимизировать бесполезно. Нужно отобрать самые проблемные и начать с них.
- [PostgreSQL](00%20PostgreSQL.md)
- Использовать [GitHub - Полезные утилиты для тюнинга PostgreSQL](https://github.com/dataegret/pg-utils) - global_reports
- Использовать [[pg_stat_statements]]
- Оптимизировать запросы
- Использовать [Explain в PostgreSQL](Explain%20в%20PostgreSQL.md) и [Explain в MySQL](Explain%20в%20MySQL.md) для анализа запросов
- Повторить с новыми запросами из топа.
**Где могут быть проблемы?**
- Передача запроса от клиента (сервиса). [Пример при использовании IN](IN%20SQL.md#Проблемы%20производительности%20IN)
- Сложный запрос, который долго парсится. Можно посмотреть в explain.
- БД долго вычисляет план запроса и проводит оптимизации. Например, при использовании join.
- Исполнение и возврат результатов. Если вы возвращаете несколько гигабайт, это не будет быстро.
**Как улучшить?**
- Переписать запрос
- Использовать [Индексы в MySQL](Индексы%20в%20MySQL.md) / [Индекс в PostgreSQL](Индекс%20в%20PostgreSQL.md)
**Невозможно улучшить**
- count(\*). Можно использовать приближенное значение из таблицы статистики.
- join на 300 таблиц
- Запрос возвращает клиенту 1 000 000 000 строк
![Почему JOIN работает медленно?](JOIN%20SQL.md#Почему%20JOIN%20работает%20медленно?)
![Проблемы производительности IN](IN%20SQL.md#Проблемы%20производительности%20IN)

View File

@ -7,8 +7,7 @@ date:
- - 2024-06-09
zero-link:
- "[[00 Базы Данных]]"
parents:
- "[[Индекс в PostgreSQL]]"
parents: []
linked:
---
Покрывающий индекс - это индекс, который включает в себя все колонки, необходимые для выполнения определенного запроса, без необходимости обращения к основной таблице данных.

View File

@ -32,6 +32,10 @@ linked:
- Устойчивость к проблемам сети
- Hot-standby реплика (VIP). Второй мастер всегда на готове, если упадет основной, но не используется.
- Offline клиенты. При плохом интернет соединении для асинхронного объединения данных. Пример БД CouchDB.
Варианты реализаций:
- Amazon Aurora
- Google Spanner
## Решение конфликтов
- Избегайте конфликтов
- Last write wins. Выигрывает последняя запись. Но обычно сложно определить кто был первым.

View File

@ -18,4 +18,9 @@ linked:
- Не ускоряет запись в БД
- Этот способ никогда не даст 99,9999 [High Availability](High%20Availability.md).
![](Pasted%20image%2020240206194227.png)
![](Pasted%20image%2020240206194227.png)
Управление master-slave:
- MHA (MySQL Master HA)
- MySQL Failover (Oracle)
- Orchestrator

View File

@ -20,6 +20,7 @@ link: https://highload.guide/blog/asynchronous-replication.html
- Обязательно убедиться, что работают GUID идентификация транзакций.
***
**Репликация сильно зависит от версии MySql**
- Всегда логическая репликация, модель master-slave, pull распространение
- 4.1 = асинхронная, SBR, logposs
@ -28,6 +29,10 @@ link: https://highload.guide/blog/asynchronous-replication.html
- 5.7 = + mtslave, +master-master (plugin), +default-RBR (image=full?!), groupcommit
## Схема работы репликации
![Архитектура MySQL](Архитектура%20MySQL.md#^42f122)
Такая плагинная архитектура позволяет устанавливать новый движок, но мгновенно возникает неоптимальность. В принципе, транзакционные write-ahead log'и (WAL), которые физический слой хранения все равно пишет, было бы хорошо использовать для репликации, и если система знает о том, что есть некий физический уровень, или достаточно хорошо сопряжена с этим физическим уровнем, то можно было бы отдельный лог на логическом уровне не писать, а использовать тот же самый WAL. Но у MySQL это невозможно концептуально, либо, если поменять интерфейс в PSE так, чтобы стало возможно концептуально, то будет очень много работы.
При включении репликации на логическом уровне MySQL мастер начинает вести binary log файл, в который сыплются все подряд изменения.
У слэйва чуть больше работы. Помимо того, чтобы вести один дополнительный лог(relay log) и по запросу его рассылать, еще есть поток, который ходит к удаленному мастеру, возможно, даже не к одному, и качает оттуда binary log'и. Еще отдельный поток пытается исполнять эти локальные логи.

View File

@ -47,6 +47,7 @@ Sync/Semi-symc:
- Нужно идентифицировать запись для update/delete (по первичному ключу/по уникальному ненуллабельному индексу/по всем столбцам).
- В случае возникновения конфликта требуется вручную исправить данные.
## Дополнительные материалы
- [Настройка репликации в PostgreSQL](Настройка%20репликации%20в%20PostgreSQL.md)
- [BDR User Guide - PostgreSQL wiki](https://wiki.postgresql.org/wiki/Logical_Log_Streaming_Replication)
- [Site Unreachable](http://www.postgresql.org/docs/9.4/static/logicaldecoding.html) Аналог [libslave](libslave.md) в MySQL
- [Отладка и устранение проблем в PostgreSQL Streaming Replication / Хабр](https://m.habr.com/ru/company/oleg-bunin/blog/414111/)

View File

@ -0,0 +1,27 @@
---
aliases:
tags:
- зрелость/🌱
date:
- - 2024-06-16
zero-link:
- "[[00 MySQL]]"
parents:
- "[[Индексы в MySQL]]"
linked:
---
![Составные индексы в БД](Составные%20индексы%20в%20БД.md)
В MySQL для составного индекса не допускаются пропуски колонок в запросе. Также индекс будет использован до первого неравенства в запросе.
Если у нас в запросе есть поиск по списку (IN), то индекс будет использоваться для списка и операций равенств, но не будет использоваться для сортировок. Лучше в таком случае использовать UNION.
Например, если у нас есть INDEX(A,B,C), то
- WHERE A = 10 AND B > 405. Индекс будет использоваться только для первой части
- WHERE A = 10 AND B = 9 AND C < 50. Индекс будет использоваться полностью.
- WHRE A = 10 AND B = 7 ORDER BY 7. Индекс будет использоваться полностью.
- WHERE B = 3; ==индекс использоваться не будет==
- WHERE A=10 AND B>4 AND C>17; Индекс будет использоваться только для первых двух частей
- WHERE A=10 ORDER BY C; Индекс будет использоваться только на первую часть
- WHERE A=10 ORDER BY B, C; Индекс будет использован целиком
- WHERE A=10 ORDER BY B, C DESC; Индекс будет использован только на первую часть. Для сортировки индекс используется только в одном направлении.

View File

@ -10,13 +10,9 @@ parents:
- "[[Индекс в PostgreSQL]]"
linked:
---
Составным называется индекс, который включает в себя несколько полей.
![Составные индексы в БД](Составные%20индексы%20в%20БД.md)
==В составных индексах важен порядок столбцов.== Порядок полей в индексе должен учитывать [селективность каждой колонки](Селективность%20колонки.md), то есть насколько уникальными являются значения в столбце. В идеале более селективные поля должны идти первыми в индексе, чтобы максимизировать эффективность индекса. ^630c7e
При поиске по составному индексу, сначала сравн иттвается первый элемент указанный в индексе, потом второй и так далее. Поэтому запросы, которые не следуют этому порядку колонок являются не оптимальными.
Частичное использование индекса. Используется до первого неравенства.
- a > 0 and b = 4. Индекс будет использоваться для всех колонок
- a = 0 and b > 3 and c = 3. Индекс будет использоваться для первых двух колонок,
- a = 0 and b > 3 and c > 3. Индекс будет использоваться только для первой колонки.
Частичное использование индекса. Используется до первого неравенства включительно.
- a > 0 and b = 4. Индекс будет использоваться для всех колонок. Не смотря на то, что первая часть это неравенство.
- a = 0 and b > 3 and c = 3. Индекс будет использоваться для первых двух колонок. После нера
- a = 0 and b > 3 and c > 3. Индекс будет использоваться для первой и второй колонки.

View File

@ -10,4 +10,11 @@ parents:
linked:
---
![](Pasted%20image%2020240608091642.png)
- Большинство существительных и прилагательных, состоящих из 2 слогов имеют ударение на первый слог.
- В глаголах из двух слогов чаще всего ударение падает на последний слог
- В составных (более одного корня) существительных чаще всего ударение падает на первый корень (первый слог).
- В составных глаголах и прилагательных ударной является вторая часть
![](Pasted%20image%2020240608091642.png)
Ударение падает на предпоследний слог ![](Pasted%20image%2020240615073511.png)

View File

@ -8,7 +8,7 @@ date:
zero-link:
- "[[00 Базы Данных]]"
parents:
- "[[SQL]]"
linked:
- "[[00 SQL]]"
linked:
---
LIKE может выполняться с индексом, но только по префиксу. Например, LIKE 'a%' - хорошо, а LIKE '%c' - плохо.

View File

@ -7,7 +7,13 @@ date:
zero-link:
- "[[00 Базы Данных]]"
parents:
- "[[SQL]]"
linked:
- "[[00 SQL]]"
linked:
---
При использовании разно-направленной сортировки (`ORDER BY a DESC, b ASC`) не используются индексы. Хотя MySQL 8+ поддерживает такие сортировки, но нужно создавать специальный разно-направленный индекс.
При использовании разно-направленной сортировки (`ORDER BY a DESC, b ASC`) не используются индексы. Хотя MySQL 8+ поддерживает такие сортировки, но нужно создавать специальный разно-направленный индекс.
ORDER BY id LIMIT 10000, 10 это плохо, т.к. сервер будет выбирать все 10 тыс. строк + еще 10, потом 1001-ю отбрасывать и только 10 выдавать. Такие вещи надо каким-то образом менять. Либо ID больше 10 000, LIMIT 10. Когда у нас offset большое число с точки зрения того, что делает сервер, это плохо.
Нельзя использовать ORDER BY rand(), т.к. эта структура делает копию всех наших данных, загоняет во временную таблицу, добавляет туда еще один столбец, куда записывает результат функции rand и потом файловую сортировку всего этого огромного массива. Поэтому, если мы хотим выбрать случайную строку, ORDER BY rand() можно применять лишь на небольших объемах данных, на больших это сразу убьет всю производительность.
Группировка по умолчанию делает и сортировку, поэтому, если нам сортировка не нужна, то мы должны указать в явном виде ORDER BY null.

View File

@ -1,15 +1,16 @@
---
aliases: []
aliases:
tags:
- зрелость/🌱
date:
- - 2024-01-29
zero-link:
- "[[00 PostgreSQL]]"
parents:
parents:
- "[[Оптимизация SQL запросов]]"
linked:
---
- [Explain](Explain.md)
- [Explain в PostgreSQL](Explain%20в%20PostgreSQL.md)
***
PostgreSQL хранит статистику по выполнениям запросов в таблице `pg_stat_user_tables`. С её помощью можно оценить какие операции PostgreSQL выполняет чаще всего.

View File

@ -9,5 +9,8 @@ zero-link:
parents:
linked:
---
- at - что-то находится у чего-то
- on - что-то на чем-то
- listen to - слушать кого-то
- leave for - уезжать куда-то
- leave for - уезжать куда-то
- waiting for - ждать кого-то

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 950 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

12
pg_stat_statements.md Normal file
View File

@ -0,0 +1,12 @@
---
aliases:
tags:
- зрелость/🌱
date:
- - 2024-06-17
zero-link:
- "[[00 PostgreSQL]]"
parents:
- "[[Профилирование запросов в PostgreSQL]]"
linked:
---

View File

@ -58,6 +58,7 @@
- [Кронштейн для телевизора](Kromax20ATLANTIS-70.jpg), который позволяет его выдвинуть вперед перед кроватью
- Коридор
- Перед входом для обуви [резиновый коврик с сотами](orig-2.webp), чтобы грязь оставалась в нем
- Автомтическая Чистилка обуви
- Офис
- Стул: herman miller
- Массажное кресло

View File

@ -27,7 +27,7 @@ link: https://www.youtube.com/watch?v=ju9F8OvnL4E
- Ориентироваться только на продуктовое окружение, так как тестовые окружения не соответствуют реальности.
- Собрать статистику нагрузки на БД от запросов.
- Инструменты для сбора статистики:
- pg_stat_statements - отличный инструмент
- [pg_stat_statements](pg_stat_statements.md) - отличный инструмент
- pgBadger - использовать с осторожностью. Собирает статистику из логов postgres. Но в логи попадают не все запросы.
- Иметь примеры запросов с параметрами.
- Для понимания входящих параметров запроса.

View File

@ -32,4 +32,7 @@ zero-link:
- [Горизонтальное масштабирование. Что, зачем, когда и как](https://highload.guide/blog/scaling-what-why-when-and-how.html)
- [Кэширование данных в web приложениях. Использование memcached](https://highload.guide/blog/caching-data-in-web-applications.html)
- [Использование memcached и Redis в высоконагруженных проектах](https://highload.guide/blog/using-memcached-and-redis.html)
- [Как мы сделали ровную балансировку нагрузки на фронтенд-кластере](https://highload.guide/blog/load-balancing-frontend-cluster.html)
- [Как мы сделали ровную балансировку нагрузки на фронтенд-кластере](https://highload.guide/blog/load-balancing-frontend-cluster.html)
- [NoSQL коротко о главном](https://highload.guide/blog/NoSQL-quick-facts.html)
- [Как выбрать In-memory NoSQL базу данных с умом. Тестируем производительность](https://highload.guide/blog/how-to-choose-In-memory-NoSQL-database.html)
- [За счет чего Tarantool такой оптимальный](https://highload.guide/blog/optimal-tarantool.html)

View File

@ -38,7 +38,7 @@ parents:
- [Шардинг](Шардирование.md)
- Виртуальные шарды
- Центральный диспетчер
- Репликация
- [Репликация](_inbox/Репликация.md)
- Партиционирование
- Кластеризация
- Денормализация

View File

@ -2,3 +2,8 @@
tags:
- type/zero-link
---
## Полезные команды
Посмотреть общее свободно дисковое место в системе
```shell
df -h
```

View File

@ -9,12 +9,32 @@ zero-link:
- [Репликация в MySQL](Репликация%20в%20MySQL.md)
- [libslave](libslave.md)
- [Бекап в MySQL](Бекап%20в%20MySQL.md)
- [Индексы в MySQL](Индексы%20в%20MySQL.md)
- [Журналы в MySQL](Журналы%20в%20MySQL.md)
- [Explain в MySQL](Explain%20в%20MySQL.md)
## Архитектура MySQL
![](Pasted%20image%2020240613195204.png)
Есть логический слой под названием MySQL, который занимается общими и изолированными от хранения данных операциями: кэширование, построение плана запроса и так далее. А есть конкретный физический слой, который отвечает за хранение данных. Он использует интерфейс подключения, то есть реализации хранилищ могут быть разными.
Логический слой, общий для всех движков:
- В управлении подключением происходит авторизация. Каждый клиент работает в своем независимом потоке. Каждый поток может кэшироваться сервером.
- Кэш запросов. Представлен одним общим потоком для всех клиентов. Может оказаться узким местом.
- Парсер. Проверяет синтаксис запроса. Проверяет наличие прав доступа. Проверяет наличие ответов в кэше запросов.
- Оптимизатор. Составляет план запроса. Из хранилища запрашивается статистика запросов.
- Исполнитель. Обращается за данными в хранилище согласно плану запроса. Обновляет значения в кэше запросов.
Индексы реализуются на уровне движка хранилища, и каждый движок может предоставлять свою реализацию одного и того же индекса.
![](Pasted%20image%2020240528082025.png)
Есть логический слой под названием MySQL, который занимается всяким общими и изолированными от хранения данных делами сеть, оптимизатор, кэши и т.д. Конкретный физический слой, который отвечает за хранение данных, лежит на этаж ниже. Есть несколько встроенных, есть ставящиеся плагинами. Но даже встроенные MyISAM, InnoDB и т.д. живут на физическом слое. Плагинная архитектура позволяет устанавливать новый движок, но мгновенно возникает неоптимальность. В принципе, транзакционные write-ahead log'и (WAL), которые физический слой хранения все равно пишет, было бы хорошо использовать для репликации, и если система знает о том, что есть некий физический уровень, или достаточно хорошо сопряжена с этим физическим уровнем, то можно было бы отдельный лог на логическом уровне не писать, а использовать тот же самый WAL. Но у MySQL это невозможно концептуально, либо, если поменять интерфейс в PSE так, чтобы стало возможно концептуально, то будет очень много работы.
- [Журналы в MySQL](Журналы%20в%20MySQL.md)
## Идентификация транзакций

View File

@ -31,4 +31,7 @@ ps aux | grep nginx
- [Кэширование на стороне Nginx](Кэширование%20на%20стороне%20Nginx.md)
- [Кэширование на стороне клиента Nginx](Кэширование%20на%20стороне%20клиента%20Nginx.md)
- [Балансировка запросов на Nginx](Балансировка%20запросов%20на%20Nginx.md)
- [GZIP сжатие в Nginx](GZIP%20сжатие%20в%20Nginx.md)
- [GZIP сжатие в Nginx](GZIP%20сжатие%20в%20Nginx.md)
## Дополнительные материалы
- [Масштабируемая конфигурация nginx](https://highload.guide/blog/scalable-configuration-nginx.html)

View File

@ -14,6 +14,9 @@ parents:
- [Репликация в PostgreSQL](Репликация%20в%20PostgreSQL.md)
- [Бэкап в PostgreSQL](Бэкап%20в%20PostgreSQL.md)
- [Профилирование запросов в PostgreSQL](Профилирование%20запросов%20в%20PostgreSQL.md)
- [Explain](Explain.md)
- [Explain в PostgreSQL](Explain%20в%20PostgreSQL.md)
- PostgreSQL пишет на диск в два места в хранилище данных и в журнал.
- PostgreSQL пишет на диск в два места в хранилище данных и в журнал.
## Дополнительные материалы
- [GitHub - Полезные утилиты для тюнинга PostgreSQL](https://github.com/dataegret/pg-utils)

View File

@ -1,7 +1,7 @@
---
aliases:
tags:
- зрелость/🌱
- type/zero-link
date:
- - 2024-02-05
zero-link:
@ -11,6 +11,9 @@ linked:
---
- Таблица - это гомогенное множество кортежей
- [IN SQL](IN%20SQL.md)
- [JOIN SQL](JOIN%20SQL.md)
## Производительность
- Всегда добавлять индекс для Foreigner key
- Подзапросы лучше, чем JOIN

View File

@ -0,0 +1,49 @@
---
aliases:
tags:
- зрелость/🌱
date:
- - 2024-06-16
zero-link:
- "[[00 MySQL]]"
parents:
linked:
---
В MysSQL есть логический слой, который занимается общими и изолированными от хранения данных операциями: кэширование, построение плана запроса и так далее. А есть конкретный физический слой, который отвечает за хранение данных. Он использует интерфейс подключения, то есть реализации хранилищ могут быть разными. ^42f122
Из-за этого возникают проблемы:
- Репликация. Вынуждены писать несколько журналов, на логическом и физическом уровне
- Индексы. Реализация одного и того же индекса может отличаться в разных хранилищах
- Оптимизатор слабо связан с хранилищем, из-за этого он не может использовать какие-то особенности движка для улучшения производительности.
![](Pasted%20image%2020240613195204.png)
Клиенты, которые обращаются к серверу через функции соответствующего коннектора или C API по протоколу TCP/IP либо UNIX Socket.
Логический слой, общий для всех движков:
- В управлении подключением происходит авторизация. Каждый клиент работает в своем независимом потоке. Каждый поток может кэшироваться сервером.
- Кэш запросов. Представлен одним общим потоком для всех клиентов. Может оказаться узким местом.
- Парсер проверяет синтаксис запроса, запрашивает у хранилищ наличие данных таблиц и полей, права доступа непосредственно к этим полям и проверяет наличие ответа в кэше запросов, после чего передает распарсенный запрос оптимизатору;
- Оптимизатор запрашивает в интерфейсе хранилищ статистику по индексам, на основании которой он строит план запроса, который передает исполнителю;
- Исполнитель. Обращается за данными в хранилище согласно плану запроса. Обновляет значения в кэше запросов.
![](Pasted%20image%2020240528082025.png)
## Оптимизатор
Выбирает самый производительный план.
План запроса, который делает оптимизатор, это не какой-то исполняемый код, а набор инструкций, который передается исполнителю. Это некое предположение о том, как запрос будет выполняться. В отличие от PostrgreSQL, мы не можем посмотреть как фактически был выполнен запрос. Данные от 2015 года, может что-то изменилось. ^432879
Какие пробоемы:
- Из-за архитектуры MySQL
- использует мало статистики по запросам.
- не учитывает особенности хранилищ, нагрузку, буфферы соединений и кэши
Как влиять на оптимизатор?
- Переписать запрос.
- Использовать [индексы](Индексы%20в%20MySQL.md)
- user/force/ignore index. Можем явно указать когда и какие индексы использовать
- straight_join. Можем задать жесткий порядок join таблиц
- @@optimizer_switch. Позволяет включать/отключать правила, которые использует оптимизатор.
- optimizer_prune_level и optimizer_search_depth. Верхняя граница количества вариантов и времени выполнения, которые рассмотрит оптимизатор.

View File

View File

@ -0,0 +1,18 @@
---
aliases:
tags:
- зрелость/🌱
date:
- - 2024-06-16
zero-link:
- "[[00 Базы Данных]]"
parents:
linked:
- "[[Составные индексы в PostgreSQL]]"
- "[[Составные индексы в MySQL]]"
---
Составным называется индекс, который включает в себя несколько полей.
==В составных индексах важен порядок столбцов.== Порядок полей в индексе должен учитывать [селективность каждой колонки](Селективность%20колонки.md), то есть насколько уникальными являются значения в столбце. В идеале более селективные поля должны идти первыми в индексе, чтобы максимизировать эффективность индекса. ^630c7e
При поиске по составному индексу, сначала сравнивается первый элемент указанный в индексе, потом второй и так далее. Поэтому запросы, которые не следуют этому порядку колонок являются не оптимальными.