sql >> Databáze >  >> RDS >> SQLite

Ladění výkonu SQLite

SQLite je oblíbená relační databáze, kterou vkládáte do své aplikace. S rostoucím množstvím dat ve vaší databázi musíte použít ladění výkonu SQLite. Tento článek pojednává o indexech a jejich úskalích, použití plánovače dotazů, režimu žurnálu Write-Ahead-Logging (WAL) a zvětšování velikosti mezipaměti. Rozvádí také důležitost měření dopadu vašich úprav pomocí automatických testů.

Úvod

SQLite je populární systém relačních databází (DB) . Na rozdíl od svých větších bratříčků založených na klient-server, jako je MySQL, SQLite lze vložit do vaší aplikace jako knihovnu . SQLite má velmi podobnou sadu funkcí a také zvládne miliony řádků, protože znáte pár tipů a triků o ladění výkonu. Jak ukážou následující části, o ladění výkonu SQLite se dá vědět víc než jen vytváření indexů.

Vytvářejte indexy, ale opatrně

Základní myšlenkou indexu je urychlit čtení konkrétních údajů , tedy SELECT příkazy s WHERE doložka. Indexy také urychlují třídění dat (ORDER BY ), nebo JOIN ingové tabulky. Indexy jsou bohužel dvousečná zbraň, protože zabírají další místo na disku a zpomalují manipulaci s daty (INSERT , UPDATE , DELETE ).

Obecná rada je vytvářet co nejméně indexů, ale tolik, kolik je třeba . Indexy mají také smysl pouze pro větší databáze s tisíci nebo miliony řádků.

K analýze dotazů použijte plánovač dotazů

Způsob, jakým jsou indexy interně používány SQLite, je zdokumentován, ale není příliš snadné porozumět. Jak je dále rozvedeno v tomto článku, je dobré analyzovat dotaz tak, že před něj přidáte EXPLAIN QUERY PLAN . Podívejte se na každý výstupní řádek, který má tři základní varianty:

  • SEARCH table ... řádky jsou dobrým znamením – SQLite používá jeden z vašich indexů!
  • SCAN table ... USING INDEX je špatné znamení,
  • SCAN table ... je ještě horší!

Zkuste se vyhnout SCAN table [using index] záznamy ve výstupu EXPLAIN QUERY PLAN kdykoli je to možné, protože u větších databází narazíte na problémy s výkonem. Použijte EXPLAIN QUERY PLAN iterativně přidávejte nebo upravujte své indexy, dokud již nebude SCAN table zobrazí se položky.

Optimalizovat dotazy, které zahrnují IS NOT

Kontrola IS NOT ... je drahý protože SQLite bude muset skenovat všechny řádky tabulky, i když má dotčený sloupec index . Indexy jsou užitečné pouze v případě, že hledáte konkrétní hodnoty, tj. srovnání zahrnující < (menší),> (větší) nebo = (rovný), ale neplatí pro !=(nerovný).

Úhledný malý trik je, že můžete nahradit WHERE column != value s WHERE column > value OR column < value . To použije index sloupce a účinně ovlivní všechny řádky, jejichž hodnota se nerovná value . Podobně WHERE stringColumn != '' lze nahradit výrazem WHERE stringColumn > '' , protože řetězce jsou seřaditelné. Při použití tohoto triku se však ujistěte, že víte, jak SQLite zpracovává NULL srovnání. Například SQLite vyhodnocuje NULL > '' jako FALSE .

Pokud takový srovnávací trik použijete, existuje další upozornění pro případ, že váš dotaz obsahuje WHERE a ORDER BY , každý s jiným sloupcem:díky tomu bude dotaz opět neefektivní. Pokud je to možné, použijte stejné ve sloupci WHERE a ORDER BY nebo vytvořte krycí index to zahrnuje jak WHERE a ORDER BY sloupec.

Zlepšete rychlost zápisu pomocí zápisu Write-Ahead-Log

Protokol Write-Ahead-Logging (WAL) režim deníku výrazně zlepšuje výkon zápisu/aktualizace ve srovnání s výchozím vrácením zpět režim deníku. Nicméně, jak je zde zdokumentováno, existuje několik upozornění . Například režim WAL není v některých operačních systémech dostupný. Existují také snížené záruky konzistence dat v případě selhání hardwaru . Nezapomeňte si přečíst několik prvních stránek, abyste pochopili, co děláte.

Zjistil jsem, že příkaz PRAGMA synchronous = NORMAL poskytuje 3-4x zrychlení. Nastavení journal_mode na WAL poté opět výrazně zlepší výkon (přibližně 10x nebo více, v závislosti na operačním systému).

Kromě upozornění, která jsem již zmínil, byste si měli být vědomi také následujícího:

  • Při použití režimu žurnálu WAL budou vedle databázového souboru na vašem souborovém systému dva další soubory, které mají stejný název jako databáze, ale s příponou „-shm“ a „-wal“. Normálně se o to nemusíte starat, ale pokud byste měli posílat databázi na jiný počítač, zatímco vaše aplikace běží, nezapomeňte tyto dva soubory zahrnout. SQLite zkomprimuje tyto dva soubory do hlavního souboru, kdykoli obvykle zavřete všechna otevřená databázová připojení.
  • Výkon vkládání nebo aktualizace se občas sníží, kdykoli dotaz spustí sloučení obsahu souboru protokolu WAL do souboru hlavní databáze. Toto se nazývá kontrolní bod , viz zde.
  • Našel jsem, že PRAGMA s, které mění journal_mode a synchronous nezdá se, že by byly trvale uloženy v databázi. Takže vždy spouštět je znovu, kdykoli otevřu nové připojení k databázi, spíše než je spouštět při prvním vytváření tabulek.

Měřte vše

Kdykoli přidáte vylepšení výkonu, nezapomeňte změřit dopad. Automatizované (jednotkové) testy jsou k tomu skvělým přístupem. Pomáhají dokumentovat vaše zjištění pro váš tým a časem odhalí odchylné chování , např. při aktualizaci na novější verzi SQLite. Příklady toho, co můžete měřit:

  • Jaký je účinek použití WAL režim deníku přes vrácení zpět režim? Jaký je účinek dalšího (prý) výkonu zvyšujícího PRAGMA s?
  • Jakmile přidáte/změníte/odeberete index, o kolik rychleji SELECT prohlášení se stanou? O kolik pomaleji je INSERT/DELETE/UPDATE prohlášení se stanou?
  • Kolik dalšího místa na disku spotřebují indexy?

U kteréhokoli z těchto testů zvažte jejich opakování s různými velikostmi databáze. Např. spusťte je na prázdné databázi a také na databázi, která již obsahuje tisíce (nebo miliony) záznamů. Měli byste také spustit testy na různých zařízeních a operačních systémech, zvláště pokud se vaše vývojové a produkční prostředí podstatně liší.

Vylaďte velikost mezipaměti

SQLite ukládá dočasné informace do mezipaměti (v paměti RAM), např. při vytváření výsledků SELECT dotazu nebo při manipulaci s daty, která ještě nebyla potvrzena. Ve výchozím nastavení je tato velikost ubohých 2 MB . Moderní stolní stroje dokážou ušetřit mnohem více. Spusťte PRAGMA cache_size = -kibibytes pro zvýšení této hodnoty (pozor na mínus podepsat před hodnotou!). Další informace naleznete zde. Opět měřte jaký dopad má toto nastavení na výkon!

Použijte REPLACE INTO k vytvoření nebo aktualizaci řádku

Nemusí to být ani tak vylepšení výkonu, jako spíše úhledný malý trik. Předpokládejme, že potřebujete aktualizovat řádek v tabulce t nebo vytvořit řádek, pokud ještě neexistuje. Namísto použití dvou dotazů (SELECT následovaný INSERT nebo UPDATE ), použijte REPLACE INTO (oficiální dokumenty).

Aby to fungovalo, přidejte další fiktivní sloupec (např. replacer ) do tabulky t , který má UNIQUE omezovat. Deklarace sloupce by mohla např. být ... replacer INTEGER UNIQUE ... který je součástí vaší CREATE TABLE prohlášení. Poté použijte dotaz jako

REPLACE INTO t (col1, col2, ..., replacer) VALUES (?,?,...,1)Code language: SQL (Structured Query Language) (sql)

Když se tento dotaz spustí poprvé, jednoduše provede INSERT . Když je spuštěn podruhé, UNIQUE omezení replacer se spustí a chování při řešení konfliktů způsobí, že starý řádek bude zrušen a automaticky se vytvoří nový. Užitečný může být také související příkaz UPSERT.

Závěr

Jakmile počet řádků ve vaší databázi naroste, stávají se vylepšení výkonu nutností. Indexy jsou nejběžnějším řešením. Vyměňují vylepšenou časovou složitost za sníženou prostorovou složitost, zlepšují rychlost čtení a zároveň negativně ovlivňují výkon modifikace dat. Ukázal jsem, že při porovnávání nerovnosti musíte být obzvláště opatrní v SELECT příkazy, protože SQLite nemůže používat indexy pro takové druhy srovnání. Obecně doporučuji používat plánovač dotazů to vysvětluje, co se stane interně pro každý dotaz SQL. Kdykoli něco upravíte, změřte dopad!


  1. Vkládání MySQL z jedné databáze do druhé

  2. Použití ovladačů Easysoft ODBC s Informatica PowerCenter

  3. Dynamicky generujte sloupce pro křížové tabulky v PostgreSQL

  4. Jak odstranit prvních 1000 řádků z tabulky pomocí SQL Server 2008?