Problém zde byl, jak jsem popsal v aktualizaci 2 mé otázky. MySQL používá indexy k rychlému provádění operací ORDER BY. Přesněji řečeno, MySQL používá B-stromy k indexování sloupců (jako jsou časová razítka – p.time/r.time), které zabírají o něco více místa, ale umožňují rychlejší řazení.
Problém s mým dotazem byl, že se třídil podle sloupce času ve dvou tabulkách s použitím časového razítka z tabulky repost, pokud je k dispozici, a tabulky příspěvků jinak. Protože MySQL neumí kombinovat B-stromy z obou tabulek, nemůže provádět rychlé řazení indexů na sloupcích ze dvou různých tabulek.
Upravil jsem svůj dotaz a strukturu tabulky dvěma způsoby, abych to vyřešil.
1) Nejprve proveďte filtrování na základě blokovaných uživatelů, takže objednávání musí být provedeno pouze u příspěvků, které jsou přístupné aktuálnímu uživateli. Toto nebyl kořen problému, ale praktická optimalizace. např.
SELECT * FROM (SELECT * FROM Post p WHERE p.author_id NOT IN (4, 5, 6...))...
2) Zacházejte s každým příspěvkem jako s repostem jeho autora, takže je zaručeno, že každý příspěvek bude mít připojitelný repost a repost.time, podle kterého se bude indexovat a třídit. např.
SELECT * FROM (...) LEFT JOIN p.reposts repost ON (p.id = repost.post_id AND
repost.time = (
SELECT MIN(r.time) FROM Repost r WHERE p.id = r.post_id
AND r.user_id IN (1, 2, 3...) AND r.user_id NOT IN (4, 5, 6...))
))
WHERE (repost.id IS NOT NULL) ORDER BY repost.time DESC LIMIT 0, 10
Na konci dne se problém změnil na ORDER BY – tento přístup zkrátil dobu dotazování z přibližně 8 sekund na 20 ms.