Скачать CV
Назад к бизнес-кейсам

MySQL

Листинг, который сортировал JSON в MySQL

ORDER BY JSON_EXTRACT заполнял временную таблицу. Сорок строк всё равно стоили filesort по пятидесяти тысячам SKU.

Листинг каталога просил у MySQL сорок опубликованных строк, по русскому title. Title жил в JSON-колонке с en, ru и de. В ORDER BY стоял JSON_EXTRACT(title, '$.ru'). EXPLAIN писал type ALL, Using filesort, Using temporary, rows 50000.

InnoDB читал JSON-блобы, чтобы их отсортировать. Buffer pool заполнялся документами, которые листинг всё равно выкинет. PHP потом снова декодировал тот же JSON. Vue SSR получал три локали для страницы, которая показывала одну.

Проблема была в сортировке документной колонки для сетки из сорока строк. Посетители ждали filesort по пятидесяти тысячам SKU. Нужна была типизированная колонка и покрывающий индекс, не JSON_EXTRACT в ORDER BY.

JSON_EXTRACT в ORDER BY индекс не берёт. Stored-колонка берёт.
JSON_EXTRACT в ORDER BY индекс не берёт. Stored-колонка берёт.

Generated-колонка

title_ru это STORED generated-колонка из JSON. SELECT листинга это id, slug, price, title_ru. Индекс (is_published, sort_order, id) покрывает эти четыре поля. sort_order маленькое целое, его ставит редактор. Сортировка по title была привычкой из админской таблицы. Публичной сетке она не нужна.

Те же сорок плиток. EXPLAIN уходит с filesort по таблице на Using index.
Те же сорок плиток. EXPLAIN уходит с filesort по таблице на Using index.

Что осталось JSON

Админская форма по-прежнему пишет объект. В UI одна локаль за раз, в строке один JSON. Публичный путь его не парсит. Horizon собирает slab в Memcached из generated-колонок, а не через json_decode() в веб-воркере.

  • innodb_buffer_pool_size перестал быть свалкой JSON каталога.
  • Handler_read_rnd_next на этом запросе ушёл с графиков.
  • Запрос листинга больше не поднимает temp table на диск, когда сортировка не влезает в sort_buffer.

JSON это формат записи. Листинг это range scan. Смешать их в одном SELECT значит, что магазин на пятьдесят тысяч SKU выглядит как полное чтение таблицы.

Какой опыт из этого

EXPLAIN на запросе листинга это первый инструмент. type ALL плюс filesort на JSON extract это не проблема кэша. Это проблема схемы.

Generated-колонки оставляют JSON админке и btree публичному пути. extract() в ORDER BY на горячем пути больше не ставлю.

Публичная сетка сортируется порядком редактора. Сортировка по title живёт в админской таблице, не в SELECT магазина.

Назад к бизнес-кейсам