Krátká odpověď je ano, primární klíč má pořadí, všechny indexy mají pořadí a primární klíč je jednoduše jedinečný index.
Jak jste správně řekli, neměli byste spoléhat na to, že se data vrátí v pořadí, v jakém jsou data uložena, optimalizátor je může vrátit v libovolném pořadí, a to bude záviset na plánu dotazů. Pokusím se však vysvětlit, proč váš dotaz funguje již 12 let.
Váš klastrovaný index jsou pouze data vaší tabulky a váš klastrovací klíč definuje pořadí, ve kterém jsou uložena. Data jsou uložena na listu a klastrovací klíč pomáhá kořenu (a přechodným poznámkám) fungovat jako ukazatele, aby se rychle dostali do pravý list pro načtení dat. Neshlukovaný index je velmi podobná struktura, ale nejnižší úroveň jednoduše obsahuje ukazatel na správnou pozici na listu seskupeného indexu.
V MySQL jsou primární klíč a seskupený index synonyma, takže primární klíč je uspořádán, ale v zásadě jde o dvě různé věci. V jiných DBMS můžete definovat jak primární klíč, tak klastrovaný index, když to uděláte, váš primární klíč se stane jedinečným neklastrovaným indexem s ukazatelem zpět na klastrovaný index.
Zjednodušeně si můžete představit tabulku se sloupcem ID, který je primárním klíčem, a dalším sloupcem (A), struktura B-stromu pro váš seskupený index by byla něco jako:
Root Node
+---+
| 1 |
+---+
Intermediate Nodes
+---+ +---+ +---+
| 1 | | 4 | | 7 |
+---+ +---+ +---+
Leaf
+-----------+ +-----------+ +-----------+
ID -> | 1 | 2 | 3 | | 4 | 5 | 6 | | 7 | 8 | 9 |
A -> | A | B | C | | D | E | F | | G | H | I |
+-----------+ +-----------+ +-----------+
Ve skutečnosti budou listové stránky mnohem větší, ale toto je pouze demo. Každá stránka má také ukazatel na další stránku a předchozí stránku pro snadné procházení stromem. Takže když uděláte dotaz jako:
SELECT ID, A
FROM T
WHERE ID > 5
LIMIT 1;
skenujete jedinečný index, takže je velmi pravděpodobné, že se bude jednat o sekvenční skenování. Velmi pravděpodobně to však není zaručeno.
MySQL prohledá kořenový uzel, pokud existuje potenciální shoda, přesune se na mezilehlé uzly, pokud by klauzule byla něco jako WHERE ID < 0
pak by MySQL vědělo, že nebyly žádné výsledky, aniž by šlo dál než ke kořenovému uzlu.
Jakmile se přesune na mezilehlý uzel, může identifikovat, že potřebuje začít na druhé stránce (mezi 4 a 7), aby mohl začít hledat ID > 5
. Takže bude postupně skenovat list počínaje druhou listovou stránkou, když již identifikoval LIMIT 1
zastaví se, jakmile najde shodu (v tomto případě 6) a vrátí tato data z listu. V tak jednoduchém příkladu se toto chování jeví jako spolehlivé a logické. Snažil jsem se vynutit výjimky výběrem hodnoty ID, o které vím, že je na konci stránky listu, abych zjistil, zda bude list naskenován v opačném pořadí, ale zatím jsem nebyl schopen toto chování vyvolat, to však neznamená to se nestane, nebo že budoucí verze MySQL to neudělají ve scénářích, které jsem testoval.
Zkrátka stačí přidat objednávku, nebo použít MIN(ID) a hotovo. Neztrácel bych příliš mnoho spánku, když bych se snažil ponořit se do vnitřního fungování optimalizátoru dotazů, abych zjistil, jaký druh fragmentace nebo rozsahy dat by byl zapotřebí k pozorování různého uspořádání seskupeného indexu v rámci plánu dotazů.