sql >> Databáze >  >> RDS >> MariaDB

Maximalizace účinnosti databázového dotazu pro MySQL – část první

Pomalé dotazy, neefektivní dotazy nebo dlouhotrvající dotazy jsou problémy, které pravidelně trápí DBA. Jsou vždy všudypřítomné, přesto jsou nevyhnutelnou součástí života každého, kdo je zodpovědný za správu databáze.

Špatný návrh databáze může ovlivnit efektivitu dotazu a jeho výkon. Nedostatek znalostí nebo nesprávné použití volání funkcí, uložených procedur nebo rutin může také způsobit snížení výkonu databáze a může dokonce poškodit celý databázový cluster MySQL.

U replikace master-slave jsou velmi častou příčinou těchto problémů tabulky, které postrádají primární nebo sekundární indexy. To způsobuje zpoždění slave, které může trvat velmi dlouhou dobu (v horším případě).

V tomto dvoudílném blogu seriálu vám poskytneme opakovací kurz, jak se vypořádat s maximalizací vašich databázových dotazů v MySQL, abyste zajistili vyšší efektivitu a výkon.

Vždy přidejte do svého stolu jedinečný index

Tabulky, které nemají primární nebo jedinečné klíče, obvykle způsobují velké problémy, když se data zvětšují. Když k tomu dojde, může jednoduchá úprava dat zastavit databázi. Nedostatek správných indexů a příkaz UPDATE nebo DELETE byl aplikován na konkrétní tabulku, jako plán dotazů bude MySQL zvoleno úplné skenování tabulky. To může způsobit vysoké diskové I/O pro čtení a zápis a snížit výkon vaší databáze. Viz příklad níže:

root[test]> show create table sbtest2\G

*************************** 1. row ***************************

       Table: sbtest2

Create Table: CREATE TABLE `sbtest2` (

  `id` int(10) unsigned NOT NULL,

  `k` int(10) unsigned NOT NULL DEFAULT '0',

  `c` char(120) NOT NULL DEFAULT '',

  `pad` char(60) NOT NULL DEFAULT ''

) ENGINE=InnoDB DEFAULT CHARSET=latin1

1 row in set (0.00 sec)



root[test]> explain extended update sbtest2 set k=52, pad="xx234xh1jdkHdj234" where id=57;

+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+

| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref | rows | filtered | Extra       |

+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+

|  1 | UPDATE      | sbtest2 | NULL       | ALL | NULL | NULL | NULL    | NULL | 1923216 | 100.00 | Using where |

+----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+

1 row in set, 1 warning (0.06 sec)

Tabulka s primárním klíčem má velmi dobrý plán dotazů,

root[test]> show create table sbtest3\G

*************************** 1. row ***************************

       Table: sbtest3

Create Table: CREATE TABLE `sbtest3` (

  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,

  `k` int(10) unsigned NOT NULL DEFAULT '0',

  `c` char(120) NOT NULL DEFAULT '',

  `pad` char(60) NOT NULL DEFAULT '',

  PRIMARY KEY (`id`),

  KEY `k` (`k`)

) ENGINE=InnoDB AUTO_INCREMENT=2097121 DEFAULT CHARSET=latin1

1 row in set (0.00 sec)



root[test]> explain extended update sbtest3 set k=52, pad="xx234xh1jdkHdj234" where id=57;

+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+

| id | select_type | table   | partitions | type | possible_keys | key     | key_len | ref | rows | filtered | Extra   |

+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+

|  1 | UPDATE      | sbtest3 | NULL       | range | PRIMARY | PRIMARY | 4       | const | 1 | 100.00 | Using where |

+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+

1 row in set, 1 warning (0.00 sec)

Primární nebo jedinečné klíče představují důležitou součást struktury tabulky, protože to je velmi důležité zejména při provádění údržby tabulky. Například použití nástrojů z Percona Toolkit (jako je pt-online-schema-change nebo pt-table-sync) doporučuje, abyste měli jedinečné klíče. Mějte na paměti, že PRIMARY KEY je již jedinečný klíč a primární klíč nemůže obsahovat hodnoty NULL, ale jedinečný klíč. Přiřazení hodnoty NULL primárnímu klíči může způsobit chybu jako,

ERROR 1171 (42000): All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead

U uzlů typu slave je také běžné, že v určitých případech není primární/jedinečný klíč v tabulce přítomen, což je v rozporu se strukturou tabulky. K dosažení tohoto cíle můžete použít mysqldiff nebo můžete použít mysqldump --no-data … params a spustit diff, abyste porovnali strukturu tabulky a zkontrolovali, zda existuje nějaká nesrovnalost.

Naskenovat tabulky s duplicitními indexy a poté je zahodit

Duplicitní indexy mohou také způsobit snížení výkonu, zvláště když tabulka obsahuje velké množství záznamů. MySQL musí provést několik pokusů o optimalizaci dotazu a pro kontrolu provádí více plánů dotazů. Zahrnuje skenování distribuce velkých indexů nebo statistik, což zvyšuje výkonovou režii, protože může způsobit spory o paměť nebo vysoké využití I/O paměti.

Degradace pro dotazy, když jsou v tabulce pozorovány duplicitní indexy, také atributy na saturaci fondu vyrovnávacích pamětí. To může také ovlivnit výkon MySQL, když kontrolní bod vyprázdní transakční protokoly na disk. To je způsobeno zpracováním a uložením nežádoucího indexu (což je ve skutečnosti plýtvání místem v konkrétním tabulkovém prostoru této tabulky). Vezměte na vědomí, že duplicitní indexy jsou také uloženy v tabulkovém prostoru, který také musí být uložen ve fondu vyrovnávacích pamětí.

Podívejte se na tabulku níže, která obsahuje více duplicitních klíčů:

root[test]#> show create table sbtest3\G

*************************** 1. row ***************************

       Table: sbtest3

Create Table: CREATE TABLE `sbtest3` (

  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,

  `k` int(10) unsigned NOT NULL DEFAULT '0',

  `c` char(120) NOT NULL DEFAULT '',

  `pad` char(60) NOT NULL DEFAULT '',

  PRIMARY KEY (`id`),

  KEY `k` (`k`,`pad`,`c`),

  KEY `kcp2` (`id`,`k`,`c`,`pad`),

  KEY `kcp` (`k`,`c`,`pad`),

  KEY `pck` (`pad`,`c`,`id`,`k`)

) ENGINE=InnoDB AUTO_INCREMENT=2048561 DEFAULT CHARSET=latin1

1 row in set (0.00 sec)

a má velikost 2,3GiB

root[test]#> \! du -hs /var/lib/mysql/test/sbtest3.ibd

2.3G    /var/lib/mysql/test/sbtest3.ibd

Pojďme zahodit duplicitní indexy a přestavět tabulku s neoperativní úpravou,

root[test]#> drop index kcp2 on sbtest3; drop index kcp on sbtest3 drop index pck on sbtest3;

Query OK, 0 rows affected (0.01 sec)

Records: 0  Duplicates: 0  Warnings: 0

Query OK, 0 rows affected (0.01 sec)

Records: 0  Duplicates: 0  Warnings: 0

Query OK, 0 rows affected (0.01 sec)

Records: 0  Duplicates: 0  Warnings: 0



root[test]#> alter table sbtest3 engine=innodb;

Query OK, 0 rows affected (28.23 sec)

Records: 0  Duplicates: 0  Warnings: 0



root[test]#> \! du -hs /var/lib/mysql/test/sbtest3.ibd

945M    /var/lib/mysql/test/sbtest3.ibd

Dokázal ušetřit až ~59 % původní velikosti tabulkového prostoru, což je opravdu obrovské.

K určení duplicitních indexů můžete použít pt-duplicate-checker, který úlohu zpracuje za vás.

Vylaďte svůj fond vyrovnávacích pamětí

V této sekci mám na mysli pouze úložný modul InnoDB.

Pool vyrovnávacích pamětí je důležitou součástí v prostoru jádra InnoDB. To je místo, kde InnoDB ukládá data tabulky a indexu do mezipaměti, když k němu přistupujete. Zrychluje zpracování, protože často používaná data jsou efektivně ukládána do paměti pomocí BTREE. Například, pokud máte více tabulek o velikosti>=100GiB a je k nim velký přístup, pak vám doporučujeme delegovat rychlou energetickou paměť počínaje velikostí 128GiB a začít přidělovat vyrovnávací paměti s 80 % fyzické paměti. Těch 80 % musí být efektivně monitorováno. Můžete použít SHOW ENGINE INNODB STATUS \G nebo můžete využít monitorovací software, jako je ClusterControl, který nabízí jemnozrnné monitorování, které zahrnuje buffer pool a jeho relevantní zdravotní metriky. Podle toho také nastavte proměnnou innodb_buffer_pool_instances. Můžete nastavit hodnotu větší než 8 (výchozí, pokud je innodb_buffer_pool_size>=1GiB), například 16, 24, 32 nebo 64 nebo vyšší, pokud je to nutné.

Při monitorování fondu vyrovnávacích pamětí musíte zkontrolovat globální stavovou proměnnou Innodb_buffer_pool_pages_free, která vám poskytne informace, zda je potřeba upravit fond vyrovnávacích pamětí, nebo možná zvážit, zda existují také nežádoucí nebo duplicitní indexy, které spotřebovávají vyrovnávací paměť. SHOW ENGINE INNODB STATUS \G také nabízí podrobnější aspekt informací o fondu vyrovnávacích pamětí včetně jeho jednotlivého fondu vyrovnávacích pamětí na základě počtu instancí innodb_buffer_pool_pool, které jste nastavili.

Použít FULLTEXTOVÉ indexy (ale pouze v případě potřeby)

Pomocí dotazů jako,

SELECT bookid, page, context FROM books WHERE context like '%for dummies%';

kde kontext je sloupec typu řetězec (char, varchar, text), je příkladem velmi špatného dotazu! Vytahování velkého obsahu záznamů filtrem, který musí být chamtivý, končí úplným prohledáním tabulky, a to je prostě šílené. Zvažte použití FULLTEXTOVÉHO indexu. A FULLTEXTOVÉ indexy mají design obráceného indexu. Invertované indexy ukládají seznam slov a pro každé slovo seznam dokumentů, ve kterých se slovo vyskytuje. Pro podporu proximitního vyhledávání se u každého slova ukládají také informace o poloze jako bajtový offset.

Chcete-li použít FULLTEXT pro vyhledávání nebo filtrování dat, musíte použít kombinaci syntaxe MATCH()...AGAINST a ne jako dotaz výše. Samozřejmě musíte zadat pole, které bude vaším FULLTEXTOVÝM indexovým polem.

Chcete-li vytvořit FULLTEXTOVÝ index, stačí zadat jako index FULLTEXT. Viz příklad níže:

root[minime]#> CREATE FULLTEXT INDEX aboutme_fts ON users_info(aboutme);

Query OK, 0 rows affected, 1 warning (0.49 sec)

Records: 0  Duplicates: 0  Warnings: 1



root[jbmrcd_date]#> show warnings;

+---------+------+--------------------------------------------------+

| Level   | Code | Message                                          |

+---------+------+--------------------------------------------------+

| Warning |  124 | InnoDB rebuilding table to add column FTS_DOC_ID |

+---------+------+--------------------------------------------------+

1 row in set (0.00 sec)

Ačkoli použití FULLTEXTOVÝCH indexů může nabídnout výhody při hledání slov ve velmi rozsáhlém kontextu uvnitř sloupce, také při nesprávném použití vytváří problémy.

Při FULLTEXTovém vyhledávání velké tabulky, ke které se neustále přistupuje (kde řada požadavků klientů hledá různá jedinečná klíčová slova), může být velmi náročné na procesor.

V určitých případech také nelze FULLTEXT použít. Viz tento externí blogový příspěvek. Ačkoli jsem to nezkoušel s 8.0, nevidím žádné relevantní změny. Doporučujeme nepoužívat FULLTEXT k prohledávání prostředí velkých dat, zejména u tabulek s vysokou návštěvností. Jinak zkuste využít jiné technologie, jako je Apache Lucene, Apache Solr, tsearch2 nebo Sphinx.

Nepoužívejte ve sloupcích hodnotu NULL

Sloupce, které obsahují hodnoty null, jsou v MySQL zcela v pořádku. Pokud však v indexu používáte sloupce s hodnotami null, může to ovlivnit výkon dotazu, protože optimalizátor nemůže poskytnout správný plán dotazů kvůli špatné distribuci indexu. Existují však určité způsoby optimalizace dotazů, které zahrnují hodnoty null, ale samozřejmě, pokud to vyhovuje požadavkům. Podívejte se prosím do dokumentace MySQL o Null Optimization. Můžete také zkontrolovat tento externí příspěvek, který je také užitečný.

Navrhněte svou topologii schématu a strukturu tabulek efektivně

Do určité míry vám normalizace databázových tabulek z 1NF (první normální forma) na 3NF (třetí normální forma) poskytuje určitou výhodu pro efektivitu dotazování, protože normalizované tabulky mají tendenci vyhýbat se nadbytečným záznamům. Správné plánování a návrh pro vaše tabulky je velmi důležité, protože to je způsob, jakým získáváte nebo získáváte data a každá z těchto akcí něco stojí. U normalizovaných tabulek je cílem databáze zajistit, aby každý neklíčový sloupec v každé tabulce byl přímo závislý na klíči; celý klíč a nic než klíč. Pokud je tohoto cíle dosaženo, vyplatí se to ve formě menšího propouštění, menšího počtu anomálií a vyšší efektivity.

I když má normalizace tabulek mnoho výhod, neznamená to, že musíte tímto způsobem normalizovat všechny tabulky. Návrh databáze můžete implementovat pomocí Star Schema. Navrhování tabulek pomocí Star Schema má výhodu jednodušších dotazů (vyhněte se složitým křížovým spojům), snadného načítání dat pro vytváření sestav, nabízí zvýšení výkonu, protože není potřeba používat sjednocení nebo složitá spojení nebo rychlé agregace. Implementace hvězdicového schématu je jednoduchá, ale musíte jej pečlivě plánovat, protože může způsobit velké problémy a nevýhody, když se váš stůl zvětší a vyžaduje údržbu. Star Schema (a jeho podkladové tabulky) jsou náchylné k problémům s integritou dat, takže můžete mít vysokou pravděpodobnost, že hromada vašich dat je nadbytečná. Pokud si myslíte, že tato tabulka musí být konstantní (struktura a design) a je navržena tak, aby využívala efektivitu dotazů, pak je to ideální případ pro tento přístup.

Míchání návrhů databází (pokud jste schopni určit a identifikovat, jaký druh dat je třeba načíst do vašich tabulek) je velmi důležité, protože můžete využívat efektivnější dotazy a také pomoci správci databází se zálohováním, údržbou a obnovou.

Zbavte se konstantních a starých dat

Nedávno jsme napsali několik doporučených postupů pro archivaci databáze v cloudu. Zabývá se tím, jak můžete využít výhod archivace dat před jejich přesunem do cloudu. Jak tedy odstranění starých dat nebo archivace vašich stálých a starých dat pomůže k efektivitě dotazování? Jak bylo uvedeno v mém předchozím blogu, existují výhody pro větší tabulky, které jsou neustále upravovány a vkládány s novými daty, tabulkový prostor může rychle růst. MySQL a InnoDB fungují efektivně, když jsou záznamy nebo data na sebe navazující a mají význam pro další řádek v tabulce. To znamená, že pokud nemáte žádné staré záznamy, které již není třeba používat, pak je optimalizátor nemusí zahrnout do statistik, které nabízejí mnohem efektivnější výsledky. Dává to smysl, že? A také efektivita dotazů není pouze na straně aplikace, ale je také potřeba zvážit její efektivitu při provádění zálohování a při údržbě nebo přepnutí při selhání. Pokud máte například špatný a dlouhý dotaz, který může ovlivnit období údržby nebo převzetí služeb při selhání, může to být problém.

Povolte protokolování dotazů podle potřeby

Vždy nastavte protokol pomalých dotazů MySQL podle svých vlastních potřeb. Pokud používáte Percona Server, můžete využít jejich rozšířené pomalé protokolování dotazů. Umožňuje vám běžně definovat určité proměnné. Můžete filtrovat typy dotazů v kombinaci, jako je full_scan, full_join, tmp_table atd. Můžete také diktovat rychlost pomalého protokolování dotazů pomocí proměnné log_slow_rate_type a mnoha dalších.

Význam povolení protokolování dotazů v MySQL (jako je pomalý dotaz) je výhodný pro kontrolu vašich dotazů, abyste mohli optimalizovat nebo vyladit MySQL úpravou určitých proměnných, které vyhovují vašim požadavkům. Chcete-li povolit protokol pomalých dotazů, ujistěte se, že jsou nastaveny tyto proměnné:

  • long_query_time – přiřaďte správnou hodnotu, jak dlouho mohou dotazy trvat. Pokud dotazy trvají déle než 10 sekund (výchozí), spadnou do souboru protokolu pomalého dotazu, který jste přiřadili.
  • slow_query_log – chcete-li jej povolit, nastavte jej na 1.
  • slow_query_log_file – toto je cílová cesta pro váš soubor protokolu pomalého dotazu.

Protokol pomalých dotazů je velmi užitečný pro analýzu dotazů a diagnostiku špatných dotazů, které způsobují zasekávání, zpoždění podřízených zařízení, dlouhé dotazy, náročné na paměť nebo CPU nebo dokonce způsobují pád serveru. Pokud používáte pt-query-digest nebo pt-index-usage, použijte jako zdrojový cíl pro hlášení těchto dotazů soubor protokolu pomalého dotazu.

Závěr

V tomto blogu jsme probrali několik způsobů, jak můžete maximalizovat efektivitu dotazů v databázi. V této další části probereme ještě další faktory, které vám mohou pomoci maximalizovat výkon. Zůstaňte naladěni!


  1. Převeďte datum a čas JS na datum a čas MySQL

  2. Jak vypočítat čtverec v SQL

  3. Homebrew postgres zlomený

  4. Vytvořte tabulku pouze v případě, že v MariaDB neexistuje