diff --git a/.obsidian/graph.json b/.obsidian/graph.json index 7f95e3f4..505b117e 100644 --- a/.obsidian/graph.json +++ b/.obsidian/graph.json @@ -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 } \ No newline at end of file diff --git a/.obsidian/hotkeys.json b/.obsidian/hotkeys.json index ee3522c7..035cff82 100644 --- a/.obsidian/hotkeys.json +++ b/.obsidian/hotkeys.json @@ -374,13 +374,5 @@ ], "key": "]" } - ], - "app:delete-file": [ - { - "modifiers": [ - "Mod" - ], - "key": "Backspace" - } ] } \ No newline at end of file diff --git a/.obsidian/plugins/home-tab/data.json b/.obsidian/plugins/home-tab/data.json index 394c7f84..a3cd2cb6 100644 --- a/.obsidian/plugins/home-tab/data.json +++ b/.obsidian/plugins/home-tab/data.json @@ -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": [], diff --git a/.obsidian/plugins/obsidian-git/data.json b/.obsidian/plugins/obsidian-git/data.json index 76925253..a16e8640 100644 --- a/.obsidian/plugins/obsidian-git/data.json +++ b/.obsidian/plugins/obsidian-git/data.json @@ -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, diff --git a/.obsidian/plugins/recent-files-obsidian/data.json b/.obsidian/plugins/recent-files-obsidian/data.json index 93ec3bf3..a03c8e11 100644 --- a/.obsidian/plugins/recent-files-obsidian/data.json +++ b/.obsidian/plugins/recent-files-obsidian/data.json @@ -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": [], diff --git a/knowledge/dev/database/JOIN.md b/.trash/JOIN.md similarity index 89% rename from knowledge/dev/database/JOIN.md rename to .trash/JOIN.md index e459e58d..a62107f4 100644 --- a/knowledge/dev/database/JOIN.md +++ b/.trash/JOIN.md @@ -16,4 +16,5 @@ SELECT * FROM posts WHERE author = "Peter" JOIN comments ON posts. id = comments.post_id ``` -Индекс по `posts.id` бесполезен. Индекс по `comments.post_id` обязателен. \ No newline at end of file +Индекс по `posts.id` бесполезен. Индекс по `comments.post_id` обязателен. + diff --git a/_inbox/CAP теорема.md b/_inbox/CAP теорема.md index 32d8c9d5..9e769de7 100644 --- a/_inbox/CAP теорема.md +++ b/_inbox/CAP теорема.md @@ -16,4 +16,4 @@ CAP теорема — это принцип, описывающий фунда Согласно теореме CAP, в любой момент времени система может обеспечивать только два из этих трёх свойств. Это означает, что при разработке системы приходится принимать компромисс между этими свойствами в зависимости от требований приложения и условий эксплуатации. Например, если для системы критически важна согласованность данных и её устойчивость к разделению, возможно придётся пожертвовать её доступностью в некоторых сценариях. -Google заявляет, что их продукт Spanner якобы нарушает CAP теорему. \ No newline at end of file +Google заявляет, что их продукт Google Spanner якобы нарушает CAP теорему. \ No newline at end of file diff --git a/_inbox/Disaster recovery.md b/_inbox/Disaster recovery.md index 108ac261..75df9af6 100644 --- a/_inbox/Disaster recovery.md +++ b/_inbox/Disaster recovery.md @@ -1,14 +1,15 @@ --- -aliases: +aliases: + - DR tags: - зрелость/🌱 date: - - 2024-03-05 zero-link: - "[[00 HighLoad]]" -parents: [] +parents: linked: --- -Восстановление после катастрофы. +Восстановление после сбоев. -Потеря данных почти всегда \ No newline at end of file +Почти всегда происходит потеря данных. \ No newline at end of file diff --git a/_inbox/Explain в MySQL.md b/_inbox/Explain в MySQL.md new file mode 100644 index 00000000..6eb027fb --- /dev/null +++ b/_inbox/Explain в MySQL.md @@ -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) \ No newline at end of file diff --git a/_inbox/Explain в PostgreSQL.md b/_inbox/Explain в PostgreSQL.md new file mode 100644 index 00000000..46cc5991 --- /dev/null +++ b/_inbox/Explain в PostgreSQL.md @@ -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) \ No newline at end of file diff --git a/_inbox/Explain.md b/_inbox/Explain.md deleted file mode 100644 index 3a091456..00000000 --- a/_inbox/Explain.md +++ /dev/null @@ -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 - оптимизация с построением битовых карт для поиска. Сначала строятся битовые карты с использованием нескольких индексов, затем эти битовые карты комбинируются. \ No newline at end of file diff --git a/_inbox/Extended keys MySQL.md b/_inbox/Extended keys MySQL.md new file mode 100644 index 00000000..13ae0307 --- /dev/null +++ b/_inbox/Extended keys MySQL.md @@ -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) \ No newline at end of file diff --git a/_inbox/High Availability.md b/_inbox/High Availability.md index dc491811..6a555c1e 100644 --- a/_inbox/High Availability.md +++ b/_inbox/High Availability.md @@ -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) ## Вопросы diff --git a/_inbox/IN SQL.md b/_inbox/IN SQL.md new file mode 100644 index 00000000..85dbe5f6 --- /dev/null +++ b/_inbox/IN SQL.md @@ -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) \ No newline at end of file diff --git a/_inbox/Index condition pushdown.md b/_inbox/Index condition pushdown.md new file mode 100644 index 00000000..341d8763 --- /dev/null +++ b/_inbox/Index condition pushdown.md @@ -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) \ No newline at end of file diff --git a/_inbox/JOIN SQL.md b/_inbox/JOIN SQL.md new file mode 100644 index 00000000..2a78f19c --- /dev/null +++ b/_inbox/JOIN SQL.md @@ -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 и будет быстро и хорошо. \ No newline at end of file diff --git a/_inbox/Memcached.md b/_inbox/Memcached.md index b6e3a4bc..56d1e5d4 100644 --- a/_inbox/Memcached.md +++ b/_inbox/Memcached.md @@ -41,3 +41,5 @@ Memcached не является надежным хранилищем – воз Для распределения нагрузки и достижения отказоустойчивости вместо одного сервера memcached используется кластер из таких серверов. Сервера, входящие в кластер, могут быть сконфигурированы с различным объемом памяти, при этом общий объем кэша будет равен сумме объемов кэшей всех memcached, входящих в кластер. Процесс memcached может быть запущен на сервере, где слабо используется процессор и не загружена до предела сеть (например, на файловом сервере). При высокой нагрузке на процессор memcached может не успевать достаточно быстро отвечать на запросы, что приводит к деградации сервиса. При работе с кластером ключи распределяются по серверам, то есть каждый сервер обрабатывает часть общего массива ключей проекта. Отказоустойчивость следует из того факта, что в случае отказа одного из серверов ключи будут перераспределены по оставшимся серверам кластера. При этом, конечно же, содержимое отказавшего сервера будет потеряно (см. раздел «Потеря ключей»). Вслучае необходимости важные ключи можно хранить не на одном сервере, а дублировать на нескольких, так можно минимизировать последствия падения сервера за счет избыточности хранения. +## Дополнительные материалы +- [Web, кэширование и memcached](https://highload.guide/blog/web-caching-memcached.html) diff --git a/_inbox/Reliability.md b/_inbox/Reliability.md index 88fe3185..9342de7c 100644 --- a/_inbox/Reliability.md +++ b/_inbox/Reliability.md @@ -7,12 +7,18 @@ date: - - 2024-02-26 zero-link: - "[[00 HighLoad]]" -parents: [] +parents: linked: + - "[[High Availability]]" --- Это метод повышения [High Availability](High%20Availability.md). Обеспечивается техническими и организационными средствами. Техническое средство - избыточность: - сервисов - active-passive. Это когда запасной сервис заранее поднят, но не используется. -- данных \ No newline at end of file + - параллельные кластеры. +- данных + - [Репликация](source/курсы/otus/Архитектор%20высоких%20нагрузок%202019/Репликация.md) + +Организационные средства: +- Дежурства разработчиков и DevOps \ No newline at end of file diff --git a/_inbox/Индекс в PostgreSQL.md b/_inbox/Индекс в PostgreSQL.md index 328856d0..8c1a2486 100644 --- a/_inbox/Индекс в PostgreSQL.md +++ b/_inbox/Индекс в PostgreSQL.md @@ -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) diff --git a/_inbox/Индексы в MySQL.md b/_inbox/Индексы в MySQL.md new file mode 100644 index 00000000..ccbf9bdd --- /dev/null +++ b/_inbox/Индексы в MySQL.md @@ -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, т.е. нужно смотреть, как писать – либо списком, либо ставить <> . Он это различает. \ No newline at end of file diff --git a/_inbox/Кэширование.md b/_inbox/Кэширование.md index d9b6d1e5..95eeea2b 100644 --- a/_inbox/Кэширование.md +++ b/_inbox/Кэширование.md @@ -14,7 +14,7 @@ linked: Ускорить сложные запросы может кэширование: мы помещаем результат вычислений в некоторое хранилище (например, [Memcached](Memcached.md) или [Redis](Redis.md)), которое обладает отличными характеристиками по времени доступа к информации. Теперь вместо обращений к медленным, сложным и тяжелым backend’ам нам достаточно выполнить запрос к быстрому кэшу. -Системы используемые для кэширования обычно не являются надежными, так что не следует хранить только там какие-то важные данные. Данные можно разделить на несколько категорий: +==Системы используемые для кэширования обычно не являются надежными, так что не следует хранить только там какие-то важные данные.== Данные можно разделить на несколько категорий: - «**Можно потерять**». К этой категории относятся кэши выборок из базы данных. Потеря таких ключей не так страшна, потому что мы можем легко восстановить их значения, обратившись заново к backend’у. Однако частые потери кэшей приводят к излишним обращениям к БД. - «**Не хотелось бы потерять**». Здесь можно упомянуть счетчики посетителей сайта, просмотров ресурсов и т.п. Хоть и восстановить эти значения иногда напрямую невозможно, но значения этих ключей имеют ограниченный по времени смысл: через несколько минут их значение уже неактуально, и будет рассчитано заново. - «**Совсем не должны терять**». Кэш удобен для хранения сессий пользователей. Однако содержимое сессий не хотелось бы терять никогда – иначе пользователей на сайте будет «разлогинивать». Как попытаться избежать? Можно кластеризовать систему кэширования, так вероятность потери снижается. diff --git a/_inbox/Настройка репликации в PostgreSQL.md b/_inbox/Настройка репликации в PostgreSQL.md new file mode 100644 index 00000000..10eaa36c --- /dev/null +++ b/_inbox/Настройка репликации в PostgreSQL.md @@ -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; + ``` diff --git a/_inbox/Оптимизация SQL запросов.md b/_inbox/Оптимизация SQL запросов.md new file mode 100644 index 00000000..a95d2b98 --- /dev/null +++ b/_inbox/Оптимизация SQL запросов.md @@ -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) \ No newline at end of file diff --git a/_inbox/Покрывающий индекс.md b/_inbox/Покрывающий индекс.md index 4d430966..4902f473 100644 --- a/_inbox/Покрывающий индекс.md +++ b/_inbox/Покрывающий индекс.md @@ -7,8 +7,7 @@ date: - - 2024-06-09 zero-link: - "[[00 Базы Данных]]" -parents: - - "[[Индекс в PostgreSQL]]" +parents: [] linked: --- Покрывающий индекс - это индекс, который включает в себя все колонки, необходимые для выполнения определенного запроса, без необходимости обращения к основной таблице данных. diff --git a/_inbox/Репликация master-master.md b/_inbox/Репликация master-master.md index b3f51804..6720cea9 100644 --- a/_inbox/Репликация master-master.md +++ b/_inbox/Репликация master-master.md @@ -32,6 +32,10 @@ linked: - Устойчивость к проблемам сети - Hot-standby реплика (VIP). Второй мастер всегда на готове, если упадет основной, но не используется. - Offline клиенты. При плохом интернет соединении для асинхронного объединения данных. Пример БД CouchDB. + +Варианты реализаций: +- Amazon Aurora +- Google Spanner ## Решение конфликтов - Избегайте конфликтов - Last write wins. Выигрывает последняя запись. Но обычно сложно определить кто был первым. diff --git a/_inbox/Репликация master-slave.md b/_inbox/Репликация master-slave.md index 5d17081c..bbd63c44 100644 --- a/_inbox/Репликация master-slave.md +++ b/_inbox/Репликация master-slave.md @@ -18,4 +18,9 @@ linked: - Не ускоряет запись в БД - Этот способ никогда не даст 99,9999 [High Availability](High%20Availability.md). -![](Pasted%20image%2020240206194227.png) \ No newline at end of file +![](Pasted%20image%2020240206194227.png) + +Управление master-slave: +- MHA (MySQL Master HA) +- MySQL Failover (Oracle) +- Orchestrator \ No newline at end of file diff --git a/_inbox/Репликация в MySQL.md b/_inbox/Репликация в MySQL.md index fb70bafc..28d610ba 100644 --- a/_inbox/Репликация в MySQL.md +++ b/_inbox/Репликация в MySQL.md @@ -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'и. Еще отдельный поток пытается исполнять эти локальные логи. diff --git a/_inbox/Репликация в PostgreSQL.md b/_inbox/Репликация в PostgreSQL.md index 668640f1..347239ed 100644 --- a/_inbox/Репликация в PostgreSQL.md +++ b/_inbox/Репликация в PostgreSQL.md @@ -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/) diff --git a/_inbox/Составные индексы в MySQL.md b/_inbox/Составные индексы в MySQL.md new file mode 100644 index 00000000..abde57b8 --- /dev/null +++ b/_inbox/Составные индексы в MySQL.md @@ -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; Индекс будет использован только на первую часть. Для сортировки индекс используется только в одном направлении. \ No newline at end of file diff --git a/_inbox/Составные индексы в PostgreSQL.md b/_inbox/Составные индексы в PostgreSQL.md index ddc75496..5f02f91d 100644 --- a/_inbox/Составные индексы в PostgreSQL.md +++ b/_inbox/Составные индексы в PostgreSQL.md @@ -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. Индекс будет использоваться только для первой колонки. \ No newline at end of file +Частичное использование индекса. Используется до первого неравенства включительно. +- a > 0 and b = 4. Индекс будет использоваться для всех колонок. Не смотря на то, что первая часть это неравенство. +- a = 0 and b > 3 and c = 3. Индекс будет использоваться для первых двух колонок. После нера +- a = 0 and b > 3 and c > 3. Индекс будет использоваться для первой и второй колонки. \ No newline at end of file diff --git a/_inbox/Ударение.md b/_inbox/Ударение.md index 0667508b..86037f7d 100644 --- a/_inbox/Ударение.md +++ b/_inbox/Ударение.md @@ -10,4 +10,11 @@ parents: linked: --- -![](Pasted%20image%2020240608091642.png) \ No newline at end of file +- Большинство существительных и прилагательных, состоящих из 2 слогов имеют ударение на первый слог. +- В глаголах из двух слогов чаще всего ударение падает на последний слог +- В составных (более одного корня) существительных чаще всего ударение падает на первый корень (первый слог). +- В составных глаголах и прилагательных ударной является вторая часть + +![](Pasted%20image%2020240608091642.png) + +Ударение падает на предпоследний слог ![](Pasted%20image%2020240615073511.png) \ No newline at end of file diff --git a/knowledge/dev/database/LIKE SQL.md b/knowledge/dev/database/LIKE SQL.md index dd064d74..1dbd78ff 100644 --- a/knowledge/dev/database/LIKE SQL.md +++ b/knowledge/dev/database/LIKE SQL.md @@ -8,7 +8,7 @@ date: zero-link: - "[[00 Базы Данных]]" parents: - - "[[SQL]]" -linked: + - "[[00 SQL]]" +linked: --- LIKE может выполняться с индексом, но только по префиксу. Например, LIKE 'a%' - хорошо, а LIKE '%c' - плохо. \ No newline at end of file diff --git a/knowledge/dev/database/ORDER BY.md b/knowledge/dev/database/ORDER BY.md index 30108d2a..d429127f 100644 --- a/knowledge/dev/database/ORDER BY.md +++ b/knowledge/dev/database/ORDER BY.md @@ -7,7 +7,13 @@ date: zero-link: - "[[00 Базы Данных]]" parents: - - "[[SQL]]" -linked: + - "[[00 SQL]]" +linked: --- -При использовании разно-направленной сортировки (`ORDER BY a DESC, b ASC`) не используются индексы. Хотя MySQL 8+ поддерживает такие сортировки, но нужно создавать специальный разно-направленный индекс. \ No newline at end of file +При использовании разно-направленной сортировки (`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. \ No newline at end of file diff --git a/knowledge/dev/database/Профилирование запросов в PostgreSQL.md b/knowledge/dev/database/Профилирование запросов в PostgreSQL.md index ff335df6..569c7fc9 100644 --- a/knowledge/dev/database/Профилирование запросов в PostgreSQL.md +++ b/knowledge/dev/database/Профилирование запросов в PostgreSQL.md @@ -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 выполняет чаще всего. diff --git a/knowledge/english/Предлоги в Английском.md b/knowledge/english/Предлоги в Английском.md index f785eecd..17b7e96d 100644 --- a/knowledge/english/Предлоги в Английском.md +++ b/knowledge/english/Предлоги в Английском.md @@ -9,5 +9,8 @@ zero-link: parents: linked: --- +- at - что-то находится у чего-то +- on - что-то на чем-то - listen to - слушать кого-то -- leave for - уезжать куда-то \ No newline at end of file +- leave for - уезжать куда-то +- waiting for - ждать кого-то \ No newline at end of file diff --git a/meta/files/Pasted image 20240615073511.png b/meta/files/Pasted image 20240615073511.png new file mode 100644 index 00000000..b00d8c34 Binary files /dev/null and b/meta/files/Pasted image 20240615073511.png differ diff --git a/meta/files/Pasted image 20240616113900.png b/meta/files/Pasted image 20240616113900.png new file mode 100644 index 00000000..1af30e25 Binary files /dev/null and b/meta/files/Pasted image 20240616113900.png differ diff --git a/meta/files/Pasted image 20240616114457.png b/meta/files/Pasted image 20240616114457.png new file mode 100644 index 00000000..d298ba13 Binary files /dev/null and b/meta/files/Pasted image 20240616114457.png differ diff --git a/meta/files/Pasted image 20240616122716.png b/meta/files/Pasted image 20240616122716.png new file mode 100644 index 00000000..88cf5ec5 Binary files /dev/null and b/meta/files/Pasted image 20240616122716.png differ diff --git a/meta/files/Pasted image 20240617132203.png b/meta/files/Pasted image 20240617132203.png new file mode 100644 index 00000000..8d1ab628 Binary files /dev/null and b/meta/files/Pasted image 20240617132203.png differ diff --git a/meta/files/Pasted image 20240617132439.png b/meta/files/Pasted image 20240617132439.png new file mode 100644 index 00000000..73862bc7 Binary files /dev/null and b/meta/files/Pasted image 20240617132439.png differ diff --git a/meta/files/~$Техсессия T1 CRM_v1_без видео.pptx b/meta/files/~$Техсессия T1 CRM_v1_без видео.pptx deleted file mode 100644 index c107ab53..00000000 Binary files a/meta/files/~$Техсессия T1 CRM_v1_без видео.pptx and /dev/null differ diff --git a/pg_stat_statements.md b/pg_stat_statements.md new file mode 100644 index 00000000..97a26759 --- /dev/null +++ b/pg_stat_statements.md @@ -0,0 +1,12 @@ +--- +aliases: +tags: + - зрелость/🌱 +date: + - - 2024-06-17 +zero-link: + - "[[00 PostgreSQL]]" +parents: + - "[[Профилирование запросов в PostgreSQL]]" +linked: +--- diff --git a/projects/Ремонт квартиры/Идеи для ремонта.md b/projects/Ремонт квартиры/Идеи для ремонта.md index cd109645..42cd0ac4 100644 --- a/projects/Ремонт квартиры/Идеи для ремонта.md +++ b/projects/Ремонт квартиры/Идеи для ремонта.md @@ -58,6 +58,7 @@ - [Кронштейн для телевизора](Kromax20ATLANTIS-70.jpg), который позволяет его выдвинуть вперед перед кроватью - Коридор - Перед входом для обуви [резиновый коврик с сотами](orig-2.webp), чтобы грязь оставалась в нем + - Автомтическая Чистилка обуви - Офис - Стул: herman miller - Массажное кресло diff --git a/source/доклады/Доклад. Индексы в PostgreSQL. Как понять, что создавать.md b/source/доклады/Доклад. Индексы в PostgreSQL. Как понять, что создавать.md index 6636bc30..2ec80e8e 100644 --- a/source/доклады/Доклад. Индексы в PostgreSQL. Как понять, что создавать.md +++ b/source/доклады/Доклад. Индексы в PostgreSQL. Как понять, что создавать.md @@ -27,7 +27,7 @@ link: https://www.youtube.com/watch?v=ju9F8OvnL4E - Ориентироваться только на продуктовое окружение, так как тестовые окружения не соответствуют реальности. - Собрать статистику нагрузки на БД от запросов. - Инструменты для сбора статистики: - - pg_stat_statements - отличный инструмент + - [pg_stat_statements](pg_stat_statements.md) - отличный инструмент - pgBadger - использовать с осторожностью. Собирает статистику из логов postgres. Но в логи попадают не все запросы. - Иметь примеры запросов с параметрами. - Для понимания входящих параметров запроса. diff --git a/source/курсы/_toc/Обучающий курс от HighLoad конференции 2024.md b/source/курсы/_toc/Обучающий курс от HighLoad конференции 2024.md index b1aea63c..5ac79471 100644 --- a/source/курсы/_toc/Обучающий курс от HighLoad конференции 2024.md +++ b/source/курсы/_toc/Обучающий курс от HighLoad конференции 2024.md @@ -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) \ No newline at end of file +- [Как мы сделали ровную балансировку нагрузки на фронтенд-кластере](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) \ No newline at end of file diff --git a/wiki/zero/00 HighLoad.md b/wiki/zero/00 HighLoad.md index d34d909b..245c1df5 100644 --- a/wiki/zero/00 HighLoad.md +++ b/wiki/zero/00 HighLoad.md @@ -38,7 +38,7 @@ parents: - [Шардинг](Шардирование.md) - Виртуальные шарды - Центральный диспетчер -- Репликация +- [Репликация](_inbox/Репликация.md) - Партиционирование - Кластеризация - Денормализация diff --git a/wiki/zero/00 Linux.md b/wiki/zero/00 Linux.md index 428cf849..18c40027 100644 --- a/wiki/zero/00 Linux.md +++ b/wiki/zero/00 Linux.md @@ -2,3 +2,8 @@ tags: - type/zero-link --- +## Полезные команды +Посмотреть общее свободно дисковое место в системе +```shell +df -h +``` \ No newline at end of file diff --git a/wiki/zero/00 MySQL.md b/wiki/zero/00 MySQL.md index f4435e83..0189dba7 100644 --- a/wiki/zero/00 MySQL.md +++ b/wiki/zero/00 MySQL.md @@ -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) ## Идентификация транзакций diff --git a/wiki/zero/00 Nginx.md b/wiki/zero/00 Nginx.md index 353bb7d3..a4dc64b9 100644 --- a/wiki/zero/00 Nginx.md +++ b/wiki/zero/00 Nginx.md @@ -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) \ No newline at end of file +- [GZIP сжатие в Nginx](GZIP%20сжатие%20в%20Nginx.md) + +## Дополнительные материалы +- [Масштабируемая конфигурация nginx](https://highload.guide/blog/scalable-configuration-nginx.html) \ No newline at end of file diff --git a/wiki/zero/00 PostgreSQL.md b/wiki/zero/00 PostgreSQL.md index 6eac0938..fe76afa4 100644 --- a/wiki/zero/00 PostgreSQL.md +++ b/wiki/zero/00 PostgreSQL.md @@ -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 пишет на диск в два места – в хранилище данных и в журнал. \ No newline at end of file +- PostgreSQL пишет на диск в два места – в хранилище данных и в журнал. + +## Дополнительные материалы +- [GitHub - Полезные утилиты для тюнинга PostgreSQL](https://github.com/dataegret/pg-utils) \ No newline at end of file diff --git a/knowledge/dev/database/SQL.md b/wiki/zero/00 SQL.md similarity index 88% rename from knowledge/dev/database/SQL.md rename to wiki/zero/00 SQL.md index 32f2dd99..ad0c0ebd 100644 --- a/knowledge/dev/database/SQL.md +++ b/wiki/zero/00 SQL.md @@ -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 diff --git a/Архитектура MySQL.md b/Архитектура MySQL.md new file mode 100644 index 00000000..ff5ea138 --- /dev/null +++ b/Архитектура MySQL.md @@ -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. Верхняя граница количества вариантов и времени выполнения, которые рассмотрит оптимизатор. + + diff --git a/Без названия.md b/Без названия.md new file mode 100644 index 00000000..e69de29b diff --git a/Составные индексы в БД.md b/Составные индексы в БД.md new file mode 100644 index 00000000..9eaba1e8 --- /dev/null +++ b/Составные индексы в БД.md @@ -0,0 +1,18 @@ +--- +aliases: +tags: + - зрелость/🌱 +date: + - - 2024-06-16 +zero-link: + - "[[00 Базы Данных]]" +parents: +linked: + - "[[Составные индексы в PostgreSQL]]" + - "[[Составные индексы в MySQL]]" +--- +Составным называется индекс, который включает в себя несколько полей. + +==В составных индексах важен порядок столбцов.== Порядок полей в индексе должен учитывать [селективность каждой колонки](Селективность%20колонки.md), то есть насколько уникальными являются значения в столбце. В идеале более селективные поля должны идти первыми в индексе, чтобы максимизировать эффективность индекса. ^630c7e + +При поиске по составному индексу, сначала сравнивается первый элемент указанный в индексе, потом второй и так далее. Поэтому запросы, которые не следуют этому порядку колонок являются не оптимальными. \ No newline at end of file