Files
huncode bbedf1ae87
Build and deploy / deploy (push) Successful in 14s
revise July 2019 SQL articles
2026-07-31 10:37:50 +03:00

139 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# П17 · июль 2019 · SQL-индексы и планы PostgreSQL — тройное ревью
Статус: **принят в публикационный слой 31 июля 2026 года**. Registry
накладывает три ревизии по стабильным slug и сохраняет дату и автора базового
архива:
- <code>editorial-2019-07-practice-sql-indexes</code>;
- <code>editorial-2019-07-mechanism-sql-indexes</code>;
- <code>editorial-2019-07-field-sql-indexes</code>.
Созданы только пять файлов:
- <code>web/scripts/upgrade-2019-07.mjs</code>;
- <code>web/public/assets/editorial/2019/sql-indexes-selectivity-2019.svg</code>;
- <code>web/public/assets/editorial/2019/sql-indexes-plan-reading-2019.svg</code>;
- <code>web/public/assets/editorial/2019/sql-indexes-predicate-shape-2019.svg</code>;
- этот файл.
Модуль экспортирует ровно три revision без полей <code>date</code> и
<code>author</code>. При прямом вызове с <code>--print-revisions</code> он пишет
только JSON, совпадающий с import-safe export. SQL-фикстура находится внутри
контента как учебный, воспроизводимый сценарий; у модуля нет второго
исполняемого режима и он не меняет базу при audit.
## Проход 1. Факты и техника — пройдено
| Утверждение или решение | Первичный источник | Проверенная граница |
| --- | --- | --- |
| Планировщик выбирает план по структуре запроса и свойствам данных; при изменении селективности может выбрать другую стратегию | [PostgreSQL 11: Using EXPLAIN](https://www.postgresql.org/docs/11/using-explain.html) | Тексты не называют <code>Seq Scan</code> ошибкой. Один и тот же ключ допускает разные планы для <code>ready</code> и <code>waiting</code> |
| <code>EXPLAIN ANALYZE</code> исполняет statement и показывает фактические rows/time; rows и time на узле усреднены на один <code>loops</code> | [PostgreSQL 11: Using EXPLAIN](https://www.postgresql.org/docs/11/using-explain.html) | В статьях <code>cost</code> не превращается в миллисекунды, а маленький внутренний узел не оценивается без учёта loops |
| <code>EXPLAIN (ANALYZE, BUFFERS)</code> нужно запускать с той же осторожностью, что и исходный statement; изменяющий пример помещён в транзакцию с rollback | [PostgreSQL 11: EXPLAIN](https://www.postgresql.org/docs/11/sql-explain.html) | В материалах нет рекомендации безопасно запускать UPDATE «только ради плана» на production |
| Селективность определяется приблизительной статистикой; <code>pg_stats</code> является читаемым представлением, а <code>ANALYZE</code> обновляет статистику | [PostgreSQL 11: Statistics Used by the Planner](https://www.postgresql.org/docs/11/planner-stats.html), [PostgreSQL 11: ANALYZE](https://www.postgresql.org/docs/11/sql-analyze.html) | <code>ANALYZE</code> не обещает индексный узел: он обновляет входные данные планировщика, после чего план снимается заново |
| B-tree — кандидат для распространённых сравнений равенства и диапазона, но индекс имеет цену поддержки | [PostgreSQL 11: Index Types](https://www.postgresql.org/docs/11/indexes-types.html), [Introduction to Indexes](https://www.postgresql.org/docs/11/indexes-intro.html) | Условие «столбец проиндексирован» не выдаётся за доказательство выигрыша для массовой выборки |
| Запрос по выражению может использовать индекс на том же выражении; такой индекс вычисляется и поддерживается при записи | [PostgreSQL 11: Indexes on Expressions](https://www.postgresql.org/docs/11/indexes-expressional.html) | Предикат <code>created_at::date</code> не объявлен автоматически плохим: предложены два варианта — семантически верный range или обоснованный expression index |
| Partial index применим, когда WHERE запроса доказуемо включает его predicate; распознавание ограничено и идёт при планировании | [PostgreSQL 11: Partial Indexes](https://www.postgresql.org/docs/11/indexes-partial.html) | Prepared statement не объявлен «никогда не использующим partial index»; текст оставляет точную границу доказуемости параметризированного условия |
### Честная граница фикстуры
Фикстура создаёт изолированную схему <code>p17_sql_index_fixture</code> в
disposable-базе, миллион синтетических строк с распределением 99/1, два B-tree
индекса, <code>ANALYZE</code> и три запроса <code>EXPLAIN (ANALYZE, BUFFERS)</code>.
Она не содержит ожидаемого дерева, вычисленных миллисекунд или фиктивных
<code>actual rows</code>: это должен вывести реальный сервер с его версией,
настройками стоимости и буферами.
В среде подготовки пакета <code>psql</code> не найден и подключение к
PostgreSQL не предоставлено. Поэтому автор **не заявляет запуск базы или
измерение плана**. Это ограничение прямо написано в каждой статье и не
заменено неподтверждённым скриншотом. Перед интеграцией fixture следует
выполнить только в отдельной disposable-базе PostgreSQL 11 и сохранить:
точный SQL и параметры, версию сервера, <code>SHOW random_page_cost</code>,
<code>SHOW seq_page_cost</code>, <code>SHOW effective_cache_size</code>, plan и
контекст нагрузки.
Вердикт прохода: **пройден**. Технические утверждения привязаны к первичной
документации PostgreSQL 11; места, зависящие от конкретного контура, названы
планом проверки, а не выполненным замером.
## Проход 2. Редактура и голос М2 / 2019 — пройдено
| Ревизия | Симптом и цена в начале | Главный вопрос | Практический артефакт и ограничение |
| --- | --- | --- | --- |
| Практика | Добавили индекс, но запрос не ускорился; цена — лишняя стоимость INSERT/UPDATE без выигрыша чтения | Как различить честный Seq Scan, плохую селективность и неверную статистику | SQL-фикстура 99/1, таблица причин, <code>pg_stats</code> и маршрут EXPLAIN; нет обещания одинакового plan на каждом сервере |
| Механизм | В тикете есть скриншот с Index/Seq Scan, но нет actual rows и параметров; цена — лечить не тот узел | Как читать estimate, actual, loops, Buffers, Index Cond и Filter как единое дерево | Безопасный EXPLAIN/rollback пример, схема потока и маршрут первого расхождения; нет выдуманного production-time |
| Полевой разбор | Индекс <code>(created_at)</code> есть, а <code>created_at::date</code> всё ещё читает таблицу; цена — раздутая схема без диагноза | Как отличить selectivity, statistics и predicate shape | Инвентаризация catalog, range versus expression index и partial predicate; timezone и PREPARE оставлены явными границами |
- Первые абзацы называют «симптом», «проблему» и цену решения. Далее каждый
текст держит одну цепочку: симптом → причина → проверка → действие →
ограничение. Вместо общих оценок названы <code>rows</code>,
<code>actual rows</code>, <code>loops</code>, <code>Buffers</code>,
<code>pg_stats</code>, <code>Index Cond</code> и <code>Filter</code>.
- Голос соответствует М2 / 2019: автор уверенно работает с SQL,
PostgreSQL, серверным планом, query shape и базовой доставкой данных, но не
приписывает себе управление платформой, SLO, распределённую трассировку,
Kubernetes или продуктовые метрики поздних лет.
- Тон краткий и прагматичный. Нет абсолютов «индекс всегда ускоряет» или
«Seq Scan всегда плох». Каждый совет требует наблюдаемой проверки до DDL.
- Длина, количество разделов, таблица с <code>caption</code>/<code>thead</code>
и <code>scope</code>, код, упорядоченный маршрут, figure с alt/caption и
два или больше первичных источника дополнительно проверяются draft gate.
Вердикт прохода: **пройден**. Тексты развивают автора от практической
диагностики к более системному чтению планов, но остаются на его правдоподобной
глубине 2019 года.
## Проход 3. Визуал и выпуск — пройдено в пределах автономного пакета
- <code>sql-indexes-selectivity-2019.svg</code> сопоставляет одинаковый
индекс с двумя распределениями результата: 990 000 <code>ready</code> и
10 000 <code>waiting</code>. Нижняя карточка явно говорит сравнить rows,
actual rows, loops и Buffers, а не ждать обязательный Index Scan.
- <code>sql-indexes-plan-reading-2019.svg</code> показывает вертикальный поток
данных от scan к результату и помечает первое расхождение estimate/actual
как точку расследования. Схема не подменяет настоящий plan и не содержит
цифр, объявленных измерением.
- <code>sql-indexes-predicate-shape-2019.svg</code> отделяет индексный ключ
<code>(created_at)</code>, выражение <code>created_at::date</code> и
полуоткрытый range. Низ схемы оставляет обязательную проверку timezone и
EXPLAIN ANALYZE, чтобы скорость не сломала границу календарного дня.
- В каждом SVG есть <code>title</code>, <code>desc</code>,
<code>role="img"</code> и связка <code>aria-labelledby</code>. У картинок в
статьях есть самостоятельный содержательный alt и <code>figcaption</code>.
В SVG нет JavaScript, внешних URL или растровых вложений. Вертикальные
viewBox и короткие подписи дают масштабируемую композицию в контейнере
статьи; XML-проверка входит в выпускной набор.
- Автономный пакет не изменяет registry, поэтому не заявляет production build
или опубликованный browser-page. Реальный рендер страницы, strict audit
общего архива и build остаются задачами интегратора после подключения
revision по slug.
### Фактические проверки
```text
node --check web/scripts/upgrade-2019-07.mjs
cd web && npm run audit:draft -- scripts/upgrade-2019-07.mjs
xmllint --noout \
web/public/assets/editorial/2019/sql-indexes-selectivity-2019.svg \
web/public/assets/editorial/2019/sql-indexes-plan-reading-2019.svg \
web/public/assets/editorial/2019/sql-indexes-predicate-shape-2019.svg
```
Результат финального запуска 31 июля 2026 года:
| Проверка | Результат |
| --- | --- |
| <code>node --check</code> | PASS, синтаксис модуля корректен |
| <code>--print-revisions</code> | PASS, stdout — JSON, export import-safe и содержит ровно три revision |
| <code>npm run audit:draft -- scripts/upgrade-2019-07.mjs</code> | PASS: 11 230 / 10 655 / 10 608 знаков основного текста |
| <code>xmllint --noout</code> для трёх SVG | PASS, XML корректен |
| Scope/self-review | PASS: в рабочем дереве появились только пять разрешённых файлов; SVG не содержат script, внешних URL, <code>foreignObject</code> или растровых data URI |
После подключения registry основной редактор повторил strict audit: все три
slug прошли объём 11 230 / 10 655 / 10 608 знаков, figure, таблицу, код,
маршрут действий и источники. <code>npm run build</code> завершился с кодом 0
и сгенерировал 374 статические страницы.
Выпусковой вердикт: **принят к публикации**. <code>articles.json</code> не
менялся; registry заменяет только редакционные поля по стабильному slug.