Вы когда-нибудь задумывались, почему в 2026 году технические статьи про базы данных всё еще выглядят так же, как в 2005? Я вижу тонны статического текста, скриншоты терминалов и блоки кода, которые читатель должен копировать и запускать где-то у себя.

В этой статье я расскажу о технической реализации SQLize Embed — легковесного JS-компонента, который превращает любую страницу в живую лабораторию SQL. Я разберу, как это работает под капотом: от фронтенда на Ace Editor до изоляции выполнения запросов на бэкенде.

Проблема: «Смерть» примера кода

Типичный путь читателя туториала:

  1. Видит интересный запрос SELECT ... OVER (PARTITION BY ...).

  2. Думает: «Круто, надо попробовать на своих данных».

  3. Вспоминает, что у него стоит PostgreSQL 14, а пример для 17-й версии.

  4. Открывает Docker, ищет образ, ждет загрузки...

  5. В 50% случаев на этом этапе интерес пропадает.

Я решил сократить это расстояние до одного клика (кнопки "Run SQL").

Архитектура решения

Система состоит из трех уровней:

  1. Frontend (Embed SDK): JS-библиотека, которая инициализирует редакторы и управляет состоянием UI.

  2. Execution API: Прослойка, отвечающая за квоты, кэширование сессий и безопасность.

  3. Backend-кластер: Ферма изолированных контейнеров с различными версиями СУБД (MySQL, PostgreSQL, Oracle, MS SQL, и т.д.).

Фронтенд: Ace Editor и MutationObserver

Я выбрал Ace Editor за его производительность и гибкость. Скрипт sqlize-embed.js весит совсем немного, так как подгружает тяжелые части редактора с CDN только при наличии на странице элементов [data-sqlize-editor].

Интересный момент — работа с динамическим контентом. Если ваш сайт подгружает статьи через AJAX или использует бесконечный скролл, обычные методы инициализации не сработают. Я применил MutationObserver:

new MutationObserver((mutations) => {
    let shouldInit = false;
    mutations.forEach(m => {
        m.addedNodes.forEach(node => {
            if (node.nodeType === 1 && (node.hasAttribute('data-sqlize-editor'))) {
                shouldInit = true;
            }
        });
    });
    if (shouldInit) initSQLize();
}).observe(document.body, { childList: true, subtree: true });

Это позволяет «подхватывать» новые редакторы сразу после их появления в DOM.

Процесс выполнения запроса

Когда пользователь нажимает «Run», происходит двухфазный процесс:

  1. Phase 1: Session Hashing. Я отправляю код и версию СУБД на эндпоинт /hash.php. Сервер генерирует уникальный идентификатор сессии. Это позволяет мне не гонять огромные куски SQL кода в URL и обеспечивает базу для кэширования результатов.

  2. Phase 2: Execution & Streaming. Клиент обращается к /sqleval.php?sqlses={hash}. Сервер находит соответствующую задачу, отправляет её в нужный контейнер и возвращает результат в виде отформатированного HTML (или JSON, в зависимости от настроек).

Технические подробности бэкенда

Самое сложное — это поддержка огромного количества версий. На текущий момент SQLize поддерживает:

  • MySQL: 8.0, 9.3.0

  • PostgreSQL: от 14 до 18 (включая PostGIS)

  • MS SQL Server: от 2017 до новейшей 2025

  • Oracle: 19c, 21c, 23ai

  • MariaDB, SQLite, Firebird, ClickHouse и даже экзотику вроде SOQOL.

Внутри это работает на Docker-контейнерах с жесткими лимитами по CPU/Memory и read-only файловой системой для пользовательских запросов (если не подразумевается CREATE TABLE).

Безопасность и изоляция

При встраивании кода в чужие сайты встает вопрос безопасности (CORS, XSS). Я использую строгие политики CORS: выполнение запросов разрешено только для доменов, имеющих активную подписку. Это предотвращает нецелевое использование моих вычислительных мощностей.

Как внедрить?

Внедрение требует минимум усилий.

  1. Подключаем SDK:

<script src="https://sqlize.online/js/sqlize-embed.js"></script>
  1. Создаем контейнер:

<div data-sqlize-editor 
     data-sql-version="psql17" 
     code-rows="10">
-- Пример использования оконных функций в PostgreSQL 17
SELECT 
    name, 
    salary, 
    AVG(salary) OVER(ORDER BY salary ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) as moving_avg
FROM (VALUES ('Alice', 5000), ('Bob', 6000), ('Charlie', 7000)) AS employees(name, salary);
</div>

Атрибуты настройки:

  • data-sql-version: идентификатор движка (например, mysql93, mssql2025).

  • data-read-only: если true, пользователь увидит код, сможет его запустить, но не сможет изменить.

  • code-rows / result-rows: фиксированная высота блоков (в строках).

Цепочки запросов (Chaining): наследование контекста

Одной из самых интересных функций стала возможность связывать несколько редакторов в цепочку. Представьте, что в начале статьи вы создаете схему базы данных, а в последующих разделах постепенно наполняете её данными и выполняете сложные запросы.

Чтобы не заставлять читателя видеть (и копировать) один и тот же DDL-код в каждом блоке, я реализовал поддержку атрибутов data-sqlize-id и data-sqlize-parent. Это работает как цепочка наследования: при нажатии кнопки «Run» скрипт рекурсивно обходит дерево родителей и собирает весь код воедино перед отправкой на сервер.

Это позволяет сохранять логический контекст обучения на протяжении всей лонгрид-статьи, не перегружая визуальное пространство лишним кодом.

Что дальше?

Я активно работаю над поддержкой векторных типов данных (уже доступны в MariaDB 11.8 через мой SDK) и интеграцией с LLM для автоматического исправления ошибок в запросах прямо внутри встраиваемого редактора.

Если вы пишете про базы данных — попробуйте сделать свои статьи интерактивными. Это кардинально меняет вовлеченность аудитории.

Буду рад ответить на вопросы в комментариях! Какие СУБД вам было бы интересно увидеть в песочнице?

Комментарии (14)


  1. Tzimie
    22.01.2026 08:56

    Непонятно. На каждый запрос поднимается контейнер с MSSQL? А что если статья популярна и сто человек повезут?


    1. rozhnev Автор
      22.01.2026 08:56

      Нет, контейнер не поднимается на каждый запрос, но для каждого запроса в контейнере создается изолированная сессия


      1. Tzimie
        22.01.2026 08:56

        А create table и все stateful?


  1. rozhnev Автор
    22.01.2026 08:56

    Каждый вызов - stateless, весь код каждый раз выполняется заново в чистой базе данных, за исключением котовых баз данных, таких как Sakila, Bookings,


  1. erogov
    22.01.2026 08:56

    Штука интересная. А начальное состояние базы можно подсунуть?


    1. rozhnev Автор
      22.01.2026 08:56

      Пока есть только несколько готовых баз данных (включая bookings для PostgreSQL). Если вам нужно что-своё свяжитесь со мной - обсудим. Телеграм: @srozhnev почта: rozhnev@msn.com


      1. erogov
        22.01.2026 08:56

        Тут вот какой момент, раз уж речь о технических статьях. Что, если мы хотим сначала показать таблицу и insert-ы, а потом (в отдельных div-ах) показывать всякие запросы к этой таблице, не повторяя каждый раз вставку? Вроде это довольно-таки базовый сценарий для статей.


        1. rozhnev Автор
          22.01.2026 08:56

          Я думаю что в ближайшее время смогу предоставить решение этой проблемы.


        1. rozhnev Автор
          22.01.2026 08:56

          В качестве быстрого решения я могу реализовать цепочку контейнеров. У каждого контейнера можно будет указать родителя и каждый вызов будет собирать весь код в один и ввполнять его при запуске кода в контейнере потомке.

          https://sqlize.online/embed#chaining


  1. gorick911
    22.01.2026 08:56

    Идея отличная. Вопрос по архитектуре: правильно ли я понимаю, что выполнение полностью stateless и пользователь не может накопить состояние между запросами, кроме предустановленных демо-баз? Интересно, рассматривал ли ты режим «короткой сессии» на N запросов для более сложных туториалов или это принципиально против модели безопасности?


    1. rozhnev Автор
      22.01.2026 08:56

      Да всё верно, в данной версии каждый сниппет выполняется в изолированной среде, но если будет задача на другое поведение можно будет найти решение.


    1. rozhnev Автор
      22.01.2026 08:56

      Добавил влзможность цепочек запросов.

      https://sqlize.online/embed#chaining


  1. Gippsland
    22.01.2026 08:56

    Можно ли взглянуть на исходный код?


    1. rozhnev Автор
      22.01.2026 08:56

      Фронта - да. Скачайте скрипт и изучайте, может подскажете как улучшить.

      Бэк я предпочитаю не открывать.