Eine Liste, die JSON in MySQL sortierte
ORDER BY JSON_EXTRACT füllte eine Temp-Tabelle. Vierzig Zeilen kosteten trotzdem einen Filesort über fünfzigtausend SKUs.
Die Katalogliste bat MySQL um vierzig veröffentlichte Zeilen, sortiert nach dem russischen Titel. Der Titel lag in einer JSON-Spalte mit en, ru und de. ORDER BY nutzte JSON_EXTRACT(title, '$.ru'). EXPLAIN sagte type ALL, Using filesort, Using temporary, rows 50000.
InnoDB las die JSON-Blobs, um sie zu sortieren. Der Buffer Pool füllte sich mit Dokumenten, die die Liste wegwirft. PHP dekodierte dasselbe JSON danach noch einmal. Vue SSR bekam drei Locales für eine Seite, die eine zeigte.
Das Problem war, eine Dokument-Spalte für ein Raster mit vierzig Zeilen zu sortieren. Besucher warteten auf einen Filesort über fünfzigtausend SKUs. Ich brauchte eine typisierte Spalte und einen Covering-Index, nicht JSON_EXTRACT in ORDER BY.
Die generated Spalte
title_ru ist eine STORED generated Spalte aus dem JSON. Das Listen-SELECT ist id, slug, price, title_ru. Der Index (is_published, sort_order, id) deckt diese vier Felder ab. sort_order ist eine kleine Zahl vom Editor. Titelsortierung war eine Gewohnheit aus der Admin-Tabelle. Das öffentliche Raster brauchte sie nicht.
Was JSON bleibt
Das Admin-Formular schreibt weiter das Objekt. Eine Locale in der UI, ein JSON-Dokument in der Zeile. Der öffentliche Pfad parst es nicht. Horizon baut den Memcached-Slab aus den generated Spalten, nicht über json_decode() im Web-Worker.
- innodb_buffer_pool_size war kein Dump des Katalog-JSON mehr.
- Handler_read_rnd_next dieser Query verschwand von den Graphen.
- Die Listenquery legt keine Temp-Tabelle auf Disk mehr an, wenn der Sort nicht in sort_buffer passt.
JSON ist ein Schreibformat. Eine Liste ist ein Range Scan. Beides in einem SELECT zu mischen macht aus einem Shop mit fünfzigtausend SKUs einen Full Table Read.
Was ich daraus mitnehme
EXPLAIN auf der Listenquery ist das erste Werkzeug. type ALL plus Filesort auf einem JSON-Extract ist kein Cache-Problem. Es ist ein Schema-Problem.
Generated-Spalten lassen Admin bei JSON und den öffentlichen Pfad bei einem Btree. extract() sortiere ich auf dem Hot Path nicht mehr.
Das öffentliche Raster sortiert nach Editor-Ordnung. Titelsortierung gehört in die Admin-Tabelle, nicht ins Shop-SELECT.
