Jak optimalizovat SQL dotazy ve velkých databázích

  • Návrh a údržba vhodných indexů spolu s aktuálními statistikami je pro optimalizátora klíčová při výběru efektivních plánů provádění u velkých databází.
  • Přepisování dotazů, aby se zabránilo použití SELECT *, funkcí na indexovaných sloupcích, korelovaných poddotazů a stránkování s velkým OFFSET, výrazně zkracuje časy a snižuje spotřebu zdrojů.
  • Kombinované využití efektivního stránkování, materializovaných pohledů, parametrizovaných dotazů a průběžného monitorování umožňuje škálování náročných SQL aplikací s větší stabilitou.

Optimalizace SQL dotazů ve velkých databázích

the špatně formulované SQL dotazy Toto jsou jedny z nejčastějších důvodů, proč aplikace běží pomalu při práci s velkými relačními databázemi, jako jsou MySQL, PostgreSQL, SQL Server, Oracle nebo DB2. I když dnes máme výkonné servery a elastické cloudy, neefektivní dotazy vás nakonec budou stát peníze. vyšší náklady na infrastrukturu, vyšší latence a horší uživatelský zážitek.

Optimalizace SQL dotazů ve velkých databázích jde daleko za rámec pouhého „přidání indexu a to je vše“. Zahrnuje Pochopení myšlení optimalizátoru dotazůJak jsou data uložena, jaké přístupové vzorce vaše aplikace používá a jaké kombinované techniky vám umožňují snížit využití I/O, CPU a paměti. V následujících částech si podrobně a s příklady probereme Nejefektivnější strategie, jak co nejlépe využít relační databáze.

Co je vlastně optimalizace SQL dotazů a proč na ní záleží?

Optimalizace SQL dotazu To znamená jeho přepsání (a úpravu kontextu: indexů, statistik, návrhu) tak, aby engine vracel stejný výsledek při menší spotřebě zdrojů a za kratší dobu. Syntaxe SQL umožňuje mnoho způsobů, jak vyjádřit tutéž věc, ale ne všechny se provedou stejně rychle, zejména když existují… miliony řádků nebo komplexních spojení.

Když vývojář pochopí, jak to funguje plánovač dotazů S vaším enginem (PostgreSQL, MySQL, SQL Server, Oracle, DB2 atd.) můžete psát dotazy, které lépe využívají indexy, snižují zbytečné čtení a minimalizují nákladné operace, jako je řazení, sekvenční prohledávání nebo opakované korelované poddotazy.

Je však důležité si ujasnit, že Optimalizace dotazů není jediným faktorem výkonuNávrh schématu (normalizace, primární a cizí klíče, datové typy), architektura (repliky, oddíly, mezipaměti) a samotná infrastruktura mají významný vliv. Ale i s dobrou architekturou může být jediný špatně optimalizovaný dotaz velkým problémem. brutální úzké hrdlo.

Mezi výhody práce v konzultačních systémech patří: celkové zlepšení výkonu (více žádostí vyřízených za kratší dobu), snížení nákladů na cloud (méně CPU a disku, menší velikosti instancí) a hladší uživatelský zážitek zkrácením čekacích dob ve výpisech, vyhledávání a přehledech. Kromě toho jsou jasné a dobře strukturované dotazy snadnější údržba a ladění, což je velmi ceněno, když projekt roste.

V aplikacích, které se skutečně zaměřují na škálování, se kontinuální optimalizace dotazů stává opakujícím se úkolem: monitorovat, detekovat, měřit, upravovat a přeměřovatNejde o jednorázovou akci, ale o proces.

Výkon SQL dotazů

Praktický příklad: stejný dotaz, velmi odlišný výkon

Abyste své myšlenky přiblížili realitě, představte si stůl objednávky s více než 20 miliony záznamů Na e-shopu chceme načíst dokončené objednávky zákazníka za posledních 30 dní a bez velkého přemýšlení bychom mohli napsat něco jako toto:

SELECT * FROM pedidos
WHERE cliente_id = 456
AND LOWER(estado) = 'completado'
AND fecha_creacion BETWEEN NOW() - INTERVAL '30 days' AND NOW();

Tento dotaz vrací, co chceme, ale z hlediska výkonu je to trochu zmatek: používá SELECT *, aplikuje funkci (LOWER) na sloupci filtru a kombinuje data s výrazy, které mohou narušovat použití indexů. Pokud navíc na client_id, status nebo creation_date, bude engine nucen prohledat velkou část tabulky.

Praktické důsledky jsou jasné: Přeneseno více dat, než je nutnéVíce práce pro backend mapující nepoužívané sloupce, velké množství čtení z disku a doba provádění, která u velmi velkých tabulek může prudce vzrůst až na několik sekund, což při mnohonásobném spuštění ovlivňuje celý systém.

Stejná otázka, formulovaná inteligentněji, by mohla vypadat takto:

SELECT id, fecha_creacion, total
FROM pedidos
WHERE cliente_id = 456
AND estado = 'Completado'
AND fecha_creacion >= CURRENT_DATE - INTERVAL '30 days'
ORDER BY fecha_creacion DESC
LIMIT 100;

Tady jsme výběr pouze potřebných sloupcůvyhýbání se funkcím ve sloupci stav, zjednodušení podmínky data a omezení počtu řádků. S dobře navrženými indexy (například INDEX(cliente_id, fecha_creacion) a jeden o estado (pokud má vysokou mohutnost), může engine použít prohledávání indexů a vyřešit dotaz v milisekundy místo sekund.

Tento kontrast ilustruje klíčovou myšlenku: Nestačí, aby dotaz „fungoval“.Musíte se starat o to, jak to běží, když tabulka už nemá stovky řádků, ale miliony.

Indexy: hlavní páka pro urychlení vyhledávání

L Indexy jsou nejúčinnějším nástrojem pro zrychlení dotazů. ve velkých databázích. Místo procházení celé tabulky řádek po řádku (sekvenční skenování nebo Seq Scan), engine používá pomocné struktury (obvykle B-stromy, R-stromy nebo haše, v závislosti na datovém typu a enginu), které umožňují přímý přechod na kandidátské řádky.

Například v MySQL jsou nejběžnější struktury stromy B pro indexy typů PRIMARY KEY, UNIQUE, INDEX y FULLTEXT, zatímco prostorové indexy používají R stromy a tabulky v paměti mohou stahovat data z indexů na základě hašišeKaždý z nich je optimalizován pro specifický přístupový vzorec.

Nejde však o indexování všeho. Každý další index Zabírá místo na disku a zpomaluje vkládání, aktualizace a mazání.protože motor musí udržovat strukturu synchronizovanou. Trik spočívá v nalezení rovnováha mezi počtem indexů a dobou odezvy, se zaměřením na otázky kritického čtení.

Mezi nejběžnější typy indexů v relačních enginech patří ty primární klíč (jednoznačně identifikují každý řádek a nepovolují hodnoty null), ty z cizí klíč (odkaz na PK jiné tabulky), unikátní indexy (zaručují jedinečnost, ale povolují null hodnoty) a složené indexy na několik sloupců, což je velmi užitečné při filtrování nebo řazení podle více polí najednou.

Indexy pro optimalizaci SQL dotazů

Existují také scénáře, kdy je užitečné použít indexy s opakujícími se hodnotami (pro urychlení vyhledávání v nejedinečných sloupcích) nebo fulltextové indexy (FULLTEXT například v MySQL) pro zlepšení vyhledávání v dlouhých textových polích. Od verze MySQL 8.0.13 lze tyto vytvářet funkční indexyTedy na základě výsledku výrazu nebo funkce (například YEAR(fecha_pago)), což otevírá dveře k pokročilým optimalizacím.

Indexy v MySQL můžeme vytvářet různými příkazy: CREATE INDEX, jejich pozdější přidání; ALTER TABLEupravit existující tabulku; nebo přímo v definici pomocí CREATE TABLEVe všech třech případech jsou povoleny jednoduché, složené, jedinečné a prefixové indexy (pouze prvních N znaků indexu VARCHAR) nebo FULLTEXT, v závislosti na návrhu, který potřebujeme.

Použití prefixové indexy To je užitečné, když máme dlouhé řetězce, ale relativně malý počet znaků stačí k rozlišení prakticky všech hodnot. Tímto způsobem zmenšíme velikost indexů, aniž bychom ztratili příliš mnoho selektivity, což je velmi užitečné ve sloupcích, jako jsou jména zákazníků, kde můžeme indexovat například prvních 25 znaků místo celého pole.

Vyberte pouze sloupce, které potřebujete

Zneužívání SELECT * Je to jeden z nejčastějších špatných návyků v SQL. Během vývoje je to pohodlné, ale v produkčním prostředí se to stává přítěží: Každý další sloupec znamená více bajtů cestujících z databáze až na vaši aplikaci, více paměti na straně klienta a více práce s deserializací.

Pokud tabulka obsahuje velké sloupce (BLOBy, velké soubory JSON, obrovské textové soubory, binární avatary atd.), jejich zahrnutí zbytečně zvyšuje využití I/O operací a RAM. Navíc v enginech, jako je PostgreSQL, umožňuje omezení počtu sloupců lepší výkon. Skenování pouze indexu, kde databáze reaguje z indexu bez nutnosti přechodu na haldu, ale to funguje pouze v případě, že všechny požadované sloupce jsou v indexu.

Klasický příklad: stůl users se sloupci jako ID, e-mail, hash hesla, avatar, vytvořeno_v_datu, poslední_přihlášeníPokud hodíte SELECT * FROM users WHERE email = '[email protected]';Hash hesla a binární avatar dostanete, i když chcete zobrazit pouze e-mail a datum posledního přihlášení. Je mnohem lepší si o to prostě požádat. id, email, last_login.

Vždy pracujte s explicitní seznamy sloupců Zpřehledňuje vaše dotazy, chrání vás před změnami schématu (přidání sloupce nic nenaruší) a dramaticky snižuje spotřebu zdrojů ve velkých tabulkách nebo stránkovaných seznamech, což pomáhá spravovat velké množství dat.

JOINy, poddotazy a CTE: jak správně strukturovat složité dotazy

the korelované poddotazy (Ty, které se provádějí jednou pro každý řádek vnějšího dotazu) se mohou na papíře zdát elegantní, ale v praxi se s rostoucími tabulkami stávají úzkým hrdlem výkonu. Každý řádek v hlavní tabulce spouští další spuštění poddotazu, což má za následek astronomický počet operací.

Kdykoli je to možné, je vhodnější transformovat tyto poddotazy do dobře indexované spojení JOIN nebo v CTE (běžné tabulkové výrazy) které rozdělují logiku do jasných kroků. Optimalizátor obvykle zvládá kombinaci tabulek mnohem lépe než hromadu složitých poddotazů.

Například pro získání produktů spolu s jejich názvem kategorie, namísto provádění poddotazu v SELECT Je efektivnější použít JOIN s tabulkou kategorií. Pokud jsou sloupce spojení indexovány (například productos.categoria_id y categorias.id), engine dokáže vyřešit spojení s velmi nízkými náklady i na velkých tabulkách.

the CTE (WITH ... AS (...)Tyto metody jsou obzvláště užitečné při vytváření dotazů, komplexních agregacích a postupné logice. I když samy o sobě ne vždy zlepšují výkon, pomáhají plánovači a především zlepšují čitelnost, usnadňují další optimalizace, jako je přidání specifických indexů nebo materializace mezivýsledků.

Stránkování a LIMIT pro zvládnutí velkých objemů

V reálných aplikacích má vracení tisíců řádků najednou z hlediska uživatelské zkušenosti téměř vždy smysl. Seznam produktů, historie objednávek nebo protokol událostí se obvykle zobrazuje stránku po stránce, takže omezit počet vrácených řádků Je to základní požadavek pro lezení.

Klasický přístup využívá LIMIT y OFFSET (například LIMIT 10 OFFSET 20 (přejděte na „třetí“ stránku). Je snadné jej implementovat a pochopit, ale má vážný problém: engine musí Projděte si všechny řádky před OFFSETem stejným způsobem.i když vrací pouze posledních 10. Ve velmi velkých tabulkách vedou vysoké hodnoty OFFSET ke stále horším dobám odezvy.

Při práci se stovkami tisíc nebo miliony řádků je obvykle lepší Stránkování klíčových sad nebo stránkování založené na vyhledáváníV tomto přístupu místo toho, abyste databázi řekli „přeskočit 1000 řádků“, jí řeknete „vrátit dalších N záznamů počínaje touto seřazenou hodnotou klíče“ s použitím podmínek typu WHERE fecha_creacion < <última_fecha_vista> s jedním ORDER BY konzistentní.

Tato technika umožňuje vyhledávacímu enginu využít výhod přímého indexu na seřazeném sloupci (například fecha_creacion o id), čímž se eliminují náklady na procházení mezistránek. Navíc to usnadňuje stránkování stabilní vůči inzercím nebo delecím mezi stránkami, což OFFSET nezaručuje.

Na oplátku má stránkování klíčových sad tu nevýhodu, že Není triviální přeskočit na stranu 37 Bez dalších informací, protože pracuje vpřed od logického kurzoru (poslední načtené ID nebo datum). Proto mnoho systémů kombinuje oba přístupy v závislosti na funkčních potřebách.

Vyhněte se funkcím ve filtrovaných sloupcích a dobře využívejte klauzuli WHERE.

Velmi častým zdrojem ztráty výkonu je použití funkce na sloupcích, které se účastní filtrůVýrazy jako LOWER(nombre), DATE(fecha) o CAST(campo AS ...) v rámci klauzule WHERE Obvykle brání optimalizátoru v použití indexu daného sloupce.

Místo toho je to lepší normalizovat data při vkládání nebo aktualizaci (například ukládání e-mailů malými písmeny, stavy s homogenním kódováním) a transformovat vstupní hodnoty tak, aby odpovídaly tomuto formátu, namísto použití funkce na sloupec v každém porovnání.

Také stojí za to věnovat pozornost samotné klauzuli. WHERE aby byl co nejselektivnější. I když pořadí podmínek nemá vždy přímý dopad (optimalizátor je obvykle přeskupí), je užitečné mít dobře indexované predikáty a jednoduchá srovnání místo drahých vzorů jako LIKE '%texto'které obvykle vynutí úplné skenování.

Pokud potřebujete odstranit duplikáty, zvažte, zda DISTINCT nebo zda by bylo možné dotaz přepracovat s JOINs přesnější nebo jedinečnější omezení v modelu. Obojí DISTINCT jak UNION obvykle zahrnují třídicí nebo seskupovací operacekteré patří v implementačním plánu k nejdražším.

Udržování indexů a statistik pro pomoc optimalizátorovi

Moderní databázové stroje se spoléhají na interní statistiky Odhadnout, kolik řádků splňuje jednotlivé podmínky, které indexy jsou nejvhodnější a v jakém pořadí spojovat tabulky. Pokud jsou tyto statistiky zastaralé, plánovač může činit velmi špatná rozhodnutí a generovat neefektivní plány provádění.

Proto je důležité pravidelně spouštět příkazy jako ANALYZE (nebo jejich specifické varianty v každém motoru) pro Obnovení statistik po velkém zatíženímigrace nebo velké objemy INSERT, UPDATE y DELETENapříklad v PostgreSQL se automatické vakuum obvykle provádí automaticky, ale po velkém importu může být užitečné spustit ANALYZE manuální.

V MySQL máme příkazy jako ANALYZE TABLE, který analyzuje a ukládá distribuci klíčů, aby pomohl optimalizátoru rozhodnout o pořadí a použití indexů v JOINsNavíc, OPTIMIZE TABLE povolit defragmentovat tabulky, přeskupovat a aktualizovat indexy, což je něco doporučeného v tabulkách, které prošly mnoha změnami.

Chcete-li zkontrolovat, zda engine používá indexy podle očekávání, není nic lepšího než vytažení z EXPLAIN o EXPLAIN ANALYZETyto nástroje nám zobrazují odhadovaný plán (a v některých vyhledávačích i skutečný plán s časy a přečtenými řádky) a indikují, zda se provádí sekvenční skenování (ALL například v MySQL) nebo pokud a Index Scankolik řádků se očekává a kolik se jich skutečně odehraje.

Naučit se číst tyto plány je pravděpodobně jednou z nejcennějších dovedností pro každého, kdo chce optimalizovat databáze: Umožňuje detekovat úzká hrdla, zbytečné indexy, špatně selektivní filtry a špatně uspořádané spojení. dlouho předtím, než se problém dostane do výroby.

Fulltextové indexy, regulární výrazy a speciální scénáře

když pracujete s velká textová pole (popisy, bohatý HTML obsah, komentáře atd.), vyhledávání s LIKE '%palabra%' Tyto se pro velké tabulky rychle stávají nepraktickými. Pro tyto případy nabízejí enginy jako MySQL indexy typu FULLTEXT a operátoři jako například MATCH() AGAINST()které umožňují mnohem efektivnější a relevantnější vyhledávání.

s FULLTEXT Můžete si vybrat mezi různými režimy: přirozený jazyk, boolean (s operátory) +, -, *(uvozovky pro přesné fráze atd.) nebo rozšíření dotazu rozšířit související výsledky. To vám umožňuje vytvářet poměrně výkonné interní vyhledávače, aniž byste museli opustit databázi.

Existují pokročilejší scénáře, kdy text obsahuje například vložené HTML tagy. V takovém případě může být nutné kombinovat index. FULLTEXT s funkcemi jako REGEXP_REPLACE k vyčištění popisků při porovnávání přesných frází. Typická strategie je nejprve filtrovat pomocí fulltextového indexu a poté použít regulární výraz v druhé podmínce, aby se výsledek zúžil na přesnou částku bez prohledávání celé tabulky.

Jiné vyhledávací enginy, jako například Oracle, umožňují použití regulární tabulkové výrazy Tyto funkce pomáhají optimalizátoru vkládat predikáty do pohledů a co nejrychleji zmenšit objem mezilehlých dat. Tento přístup je velmi užitečný při práci s mnoha vnořenými pohledy nebo složitými definicemi v prostředích pro spolupráci.

Další osvědčené postupy: parametry, materializované pohledy a rozdělení dotazů

Kromě indexů a implementačních plánů existuje řada dobré průřezové postupy které přispívají jak k výkonu, tak k bezpečnosti. Jedním z nejdůležitějších je používat parametrizované dotazy Namísto zřetězení řetězců za účelem vytvoření dynamického SQL se tím snižuje riziko SQL injection a umožňuje se databázi opakovaně používat plány provádění pro dotazy se stejnou strukturou.

V systémech s velmi těžké a opakující se dotazy (řídicí panely, manažerské zprávy, agregované výpočty), zhmotněné pohledy Jsou skvělým spojencem. Na rozdíl od běžného zobrazení fyzicky ukládají výsledek dotazu a stávají se tak jakousi předem vypočítanou tabulkou, kterou lze velmi rychle indexovat a dotazovat.

PostgreSQL, Oracle a SQL Server (s jejich indexovanými pohledy) nativně podporují materializované pohledy s různými možnostmi obnovy (manuální, plánované a v některých případech i automatické). V MySQL, protože neexistuje žádná přímá podpora, je toto chování obvykle emulováno tabulkami a procesy, které periodicky regenerují data, často prostřednictvím triggerů nebo plánovaných úloh.

Pokud dotaz spojuje příliš mnoho tabulek nebo se spoléhá na složitou mozaiku pohledů, další platnou strategií je rozdělte dotaz do několika krokůTo znamená spuštění počátečního dotazu pro získání menší sady (např. relevantních ID) a následné spuštění dalších dotazů pro doplnění informací. Tento přístup by měl být používán uvážlivě, protože může zvýšit počet přístupů k databázi, ale v některých případech drasticky snižuje složitost plánu a velikost mezilehlých sad.

V průběhu tohoto procesu se používají monitorovací nástroje, jako například pg_stat_statements, PgHero, PMM, Query Store, New Relic nebo Datadog Mohou vám pomoci rychle identifikovat, které dotazy jsou pomalejší nebo se spouštějí častěji, abyste mohli upřednostnit optimalizační úsilí tam, kde je to skutečně důležité.

Optimalizujte SQL dotazy s pomocí umělé inteligence

V posledních letech se objevily nástroje založené na umělé inteligenci které analyzují vaše dotazy a schéma databáze a navrhují vylepšení: návrhy indexů, přepisy dotazů, změny ve struktuře tabulek atd. Názvy jako EverSQL, DBScoop, PGAnalyzer nebo Redshift Advisor se staly populárními v profesionálním prostředí.

Tato řešení dokáží prohlížet velké objemy protokolů dotazů, porovnávat je se statistikami, plány provádění a metrikami výkonu a na základě toho odhalit neefektivní vzorce nebo úzká hrdla což by nám na první pohled uniklo. Pomáhají také posoudit hypotetický dopad vytvoření nebo zrušení určitých indexů.

Je však důležité chápat je jako podpora, nikoli jako náhrada Záleží na vašich znalostech SQL a pochopení vaší aplikace. Můžete obdržet návrh indexu, který teoreticky zrychlí konkrétní dotaz, ale výrazně zhorší zápisy do kritického modulu. Bez obchodního kontextu nástroj neví, na čem záleží nejvíce.

Ideální kombinací je tým, který ovládá principy optimalizace (plány, indexy, normalizaci, přístupové vzorce) a využívá umělou inteligenci k… urychlení analýzy a ověření hypotéznedělat rozhodnutí naslepo.

Když si osvojíte celou tuto sadu technik – pečlivý návrh indexů, minimální výběr sloupců, inteligentní využití spojení JOIN a CTE, efektivní stránkování, pravidelnou údržbu statistik, využití materializovaných pohledů a dokonce i podporu nástrojů umělé inteligence – Velké databáze už nejsou nekontrolovatelným monstrem a stanou se předvídatelnou a škálovatelnou součástí vaší architektury, schopnou růst s vaším podnikáním, aniž by to narušilo uživatelský zážitek nebo rozpočet na infrastrukturu.

Jak udržovat zdravou síťovou infrastrukturu ve Windows
Související článek:
Jak udržovat zdravou síťovou infrastrukturu ve Windows

Přidat jako preferovaný zdroj v Googlu