sql >> Database teknologi >  >> RDS >> MariaDB

Maksimering af databaseforespørgselseffektivitet til MySQL - del 1

Langsomme forespørgsler, ineffektive forespørgsler eller langvarige forespørgsler er problemer, der jævnligt plager DBA'er. De er altid allestedsnærværende, men er alligevel en uundgåelig del af livet for enhver, der er ansvarlig for at administrere en database.

Dårligt databasedesign kan påvirke effektiviteten af ​​forespørgslen og dens ydeevne. Manglende viden eller ukorrekt brug af funktionskald, lagrede procedurer eller rutiner kan også forårsage forringelse af databasens ydeevne og kan endda skade hele MySQL-databaseklyngen.

For en master-slave-replikering er en meget almindelig årsag til disse problemer tabeller, som mangler primære eller sekundære indekser. Dette forårsager slavelag, som kan vare i meget lang tid (i et værre tilfælde).

I denne blog i to dele af serien giver vi dig et genopfriskningskursus i, hvordan du håndterer maksimeringen af ​​dine databaseforespørgsler i MySQL for at skabe bedre effektivitet og ydeevne.

Føj altid et unikt indeks til din tabel

Tabeller, der ikke har primære eller unikke nøgler, skaber typisk enorme problemer, når data bliver større. Når dette sker, kan en simpel dataændring stoppe databasen. Mangel på korrekte indekser og en UPDATE- eller DELETE-sætning er blevet anvendt på den pågældende tabel, vil en fuld tabelscanning blive valgt som forespørgselsplan af MySQL. Det kan forårsage høj disk I/O til læsning og skrivning og forringer ydeevnen af ​​din database. Se et eksempel nedenfor:

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)

Mens en tabel med primær nøgle har en meget god forespørgselsplan,

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ære eller unikke nøgler udgør en vital komponent til en tabelstruktur, fordi dette er meget vigtigt, især når der udføres vedligeholdelse på et bord. For eksempel, ved at bruge værktøjer fra Percona Toolkit (såsom pt-online-schema-change eller pt-table-sync), anbefales det, at du skal have unikke nøgler. Husk, at den PRIMÆR NØGLE allerede er en unik nøgle, og en primær nøgle kan ikke indeholde NULL-værdier, men en unik nøgle. Tildeling af en NULL-værdi til en primærnøgle kan forårsage en fejl som,

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

For slaveknuder er det også almindeligt, at i visse tilfælde er den primære/unikke nøgle ikke til stede på bordet, hvilket derfor er uoverensstemmelser i tabelstrukturen. Du kan bruge mysqldiff til at opnå dette, eller du kan mysqldump --no-data ... params og og køre en diff for at sammenligne dens tabelstruktur og kontrollere, om der er nogen uoverensstemmelse.

Scan tabeller med duplikerede indekser, og droppede det derefter

Dubletter af indekser kan også forårsage ydeevneforringelse, især når tabellen indeholder et stort antal poster. MySQL skal udføre flere forsøg for at optimere forespørgslen og udfører flere forespørgselsplaner for at kontrollere. Det omfatter scanning af store indeksfordelinger eller statistikker, og det tilføjer ydeevneoverhead, da det kan forårsage hukommelsesstridigheder eller høj I/O-hukommelsesudnyttelse.

Forringelse for forespørgsler, når der observeres duplikerede indekser på en tabel, giver også attributter til at mætte bufferpuljen. Dette kan også påvirke ydeevnen af ​​MySQL, når checkpointingen tømmer transaktionsloggene ind på disken. Dette skyldes behandlingen og lagringen af ​​et uønsket indeks (hvilket faktisk er spild af plads i den pågældende tabels særlige tablespace). Vær opmærksom på, at duplikerede indekser også gemmes i tablespacet, som også skal gemmes i bufferpuljen.

Tag et kig på tabellen nedenfor, som indeholder flere dubletnøgler:

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)

og har en størrelse på 2,3GiB

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

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

Lad os droppe de duplikerede indekser og genopbygge tabellen med en no-op ændring,

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

Det har været i stand til at spare op til ~59 % af den gamle størrelse af bordpladsen, hvilket er virkelig enormt.

For at bestemme duplikerede indekser kan du bruge pt-duplicate-checker til at håndtere jobbet for dig.

Juster din bufferpulje

For dette afsnit refererer jeg kun til InnoDB-lagringsmotoren.

Bufferpuljen er en vigtig komponent i InnoDB-kernerummet. Det er her, InnoDB cacher tabel- og indeksdata, når de tilgås. Det fremskynder behandlingen, fordi ofte brugte data bliver lagret i hukommelsen effektivt ved hjælp af BTREE. For eksempel, hvis du har flere tabeller bestående af>=100GiB og der er meget adgang til dem, så foreslår vi, at du uddelegerer en hurtig flygtig hukommelse fra en størrelse på 128GiB og begynder at tildele bufferpuljen 80% af den fysiske hukommelse. De 80 % skal overvåges effektivt. Du kan bruge SHOW ENGINE INNODB STATUS \G, eller du kan udnytte overvågningssoftware såsom ClusterControl, som tilbyder en finmasket overvågning, som inkluderer bufferpulje og dens relevante sundhedsmålinger. Indstil også variabelen innodb_buffer_pool_instances i overensstemmelse hermed. Du kan indstille dette større end 8 (standard hvis innodb_buffer_pool_size>=1GiB), såsom 16, 24, 32 eller 64 eller højere, hvis det er nødvendigt.

Når du overvåger bufferpuljen, skal du tjekke den globale statusvariabel Innodb_buffer_pool_pages_free, som giver dig tanker om, hvorvidt der er behov for at justere bufferpuljen, eller måske overveje, om der også er uønskede eller duplikerede indekser, der bruger buffer. SHOW ENGINE INNODB STATUS \G tilbyder også et mere detaljeret aspekt af bufferpuljens information inklusive dens individuelle bufferpulje baseret på antallet af innodb_buffer_pool_instances, du har indstillet.

Brug FULLTEXT-indekser (men kun hvis det er relevant)

Brug af forespørgsler som,

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

hvor kontekst er en kolonne af strengtype (char, varchar, tekst), er et eksempel på en super dårlig forespørgsel! At trække stort indhold af poster med et filter, der skal være grådigt, ender med en fuld tabelscanning, og det er bare vanvittigt. Overvej at bruge FULLTEXT-indekset. Et FULLTEXT-indeks har et omvendt indeksdesign. Inverterede indekser gemmer en liste over ord, og for hvert ord en liste over dokumenter, som ordet optræder i. For at understøtte nærhedssøgning gemmes positionsoplysninger for hvert ord også som en byteforskydning.

For at bruge FULLTEXT til at søge eller filtrere data, skal du bruge kombinationen af ​​MATCH() ... MOD syntaks og ikke som forespørgslen ovenfor. Selvfølgelig skal du angive, at feltet skal være dit FULLTEXT-indeksfelt.

For at oprette et FULLTEXT-indeks skal du blot angive med FULLTEXT som dit indeks. Se eksemplet nedenfor:

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)

Selvom brug af FULLTEXT-indekser kan give fordele, når du søger efter ord i en meget stor kontekst inde i en kolonne, skaber det også problemer, når det bruges forkert.

Når du foretager en FULLTEXT-søgning efter en stor tabel, som der konstant er adgang til (hvor en række klientanmodninger søger efter forskellige, unikke søgeord), kan det være meget CPU-krævende.

Der er også visse tilfælde, hvor FULLTEXT ikke er relevant. Se dette eksterne blogindlæg. Selvom jeg ikke har prøvet dette med 8.0, kan jeg ikke se nogen ændringer, der er relevante for dette. Vi foreslår, at du ikke bruger FULLTEXT til at søge i et big data-miljø, især for tabeller med høj trafik. Ellers kan du prøve at udnytte andre teknologier såsom Apache Lucene, Apache Solr, tsearch2 eller Sphinx.

Undgå at bruge NULL i kolonner

Kolonner, der indeholder null-værdier, er helt fine i MySQL. Men hvis du bruger kolonner med null-værdier i et indeks, kan det påvirke forespørgselsydeevnen, da optimeringsværktøjet ikke kan levere den rigtige forespørgselsplan på grund af dårlig indeksfordeling. Der er dog visse måder at optimere forespørgsler på, der involverer nulværdier, men selvfølgelig, hvis dette passer til kravene. Se venligst dokumentationen til MySQL om Null Optimization. Du kan også tjekke dette eksterne indlæg, som også er nyttigt.

Design din skematopologi og tabelstruktur effektivt

Til en vis grad giver normalisering af dine databasetabeller fra 1NF (First Normal Form) til 3NF (Third Normal Form) dig en vis fordel for forespørgselseffektiviteten, fordi normaliserede tabeller har en tendens til at undgå overflødige poster. En ordentlig planlægning og design af dine tabeller er meget vigtig, fordi det er sådan, du hentede eller trækker data, og i hver enkelt af disse handlinger har en omkostning. Med normaliserede tabeller er målet med databasen at sikre, at hver ikke-nøglekolonne i hver tabel er direkte afhængig af nøglen; hele nøglen og intet andet end nøglen. Hvis dette mål nås, betaler det sig af fordelene i form af reducerede afskedigelser, færre anomalier og forbedret effektivitet.

Mens normalisering af dine tabeller har mange fordele, betyder det ikke, at du behøver at normalisere alle dine tabeller på denne måde. Du kan implementere et design til din database ved hjælp af Star Schema. At designe dine tabeller ved hjælp af Star Schema har fordelen ved enklere forespørgsler (undgå komplekse krydsforbindelser), let at hente data til rapportering, giver ydeevnegevinster, fordi der ikke er behov for at bruge fagforeninger eller komplekse sammenkædninger eller hurtige aggregeringer. Et stjerneskema er nemt at implementere, men du skal planlægge nøje, fordi det kan skabe store problemer og ulemper, når dit bord bliver større og kræver vedligeholdelse. Stjerneskema (og dets underliggende tabeller) er tilbøjelige til dataintegritetsproblemer, så du kan have stor sandsynlighed for, at en masse af dine data er overflødige. Hvis du mener, at denne tabel skal være konstant (struktur og design) og er designet til at udnytte forespørgselseffektivitet, så er det et ideelt tilfælde for denne tilgang.

At blande dine databasedesign (så længe du er i stand til at bestemme og identificere, hvilken slags data der skal trækkes på dine tabeller) er meget vigtigt, da du kan drage fordel af mere effektive forespørgsler og hjælpe DBA med sikkerhedskopiering, vedligeholdelse og gendannelse.

Slip af med konstante og gamle data

Vi skrev for nylig nogle bedste fremgangsmåder til arkivering af din database i skyen. Det dækker over, hvordan du kan drage fordel af dataarkivering, før det går til skyen. Så hvordan hjælper det med at forespørge effektiviteten ved at slippe af med gamle data eller arkivere dine konstante og gamle data? Som det fremgår af min tidligere blog, er der fordele ved større tabeller, der hele tiden ændres og indsættes med nye data, tablespacet kan vokse hurtigt. MySQL og InnoDB fungerer effektivt, når poster eller data støder op til hinanden og har betydning for dens næste række i tabellen. Det betyder, at hvis du ikke har gamle poster, der ikke længere skal bruges, så behøver optimeringsværktøjet ikke at inkludere det i statistikken, hvilket giver et meget mere effektivt resultat. Giver mening, ikke? Og også, forespørgselseffektivitet er ikke kun på applikationssiden, den har også behov for at overveje dens effektivitet, når der udføres en backup og ved vedligeholdelse eller failover. For eksempel, hvis du har en dårlig og lang forespørgsel, der kan påvirke din vedligeholdelsesperiode eller en failover, kan det være et problem.

Aktiver forespørgselslogning efter behov

Indstil altid din MySQL's langsomme forespørgselslog i overensstemmelse med dine tilpassede behov. Hvis du bruger Percona Server, kan du drage fordel af deres udvidede langsomme forespørgselslogning. Det giver dig mulighed for sædvanligvis at definere visse variabler. Du kan filtrere typer forespørgsler i kombination såsom fuld_scanning, fuld_join, tmp_table osv. Du kan også diktere hastigheden af ​​langsom forespørgselslogning gennem variabel log_slow_rate_type og mange andre.

Vigtigheden af ​​at aktivere forespørgselslogning i MySQL (såsom langsom forespørgsel) er en fordel for at inspicere dine forespørgsler, så du kan optimere eller tune din MySQL ved at justere visse variabler, der passer til dine krav. For at aktivere langsom forespørgselslog skal du sørge for, at disse variabler er konfigureret:

  • long_query_time - tildel den rigtige værdi for, hvor lang tid forespørgslerne kan tage. Hvis forespørgslerne tager mere end 10 sekunder (standard), vil den falde ned til den langsomme forespørgselslogfil, du har tildelt.
  • slow_query_log - for at aktivere den skal du indstille den til 1.
  • slow_query_log_file - dette er destinationsstien til din langsomme forespørgselslogfil.

Den langsomme forespørgselslog er meget nyttig til forespørgselsanalyse og diagnosticering af dårlige forespørgsler, der forårsager stall, slaveforsinkelser, langvarige forespørgsler, hukommelses- eller CPU-intensive, eller endda får serveren til at gå ned. Hvis du bruger pt-query-digest eller pt-index-usage, skal du bruge den langsomme forespørgselslogfil som dit kildemål for at rapportere disse forespørgsler ens.

Konklusion

Vi har diskuteret nogle måder, du kan bruge til at maksimere effektiviteten af ​​databaseforespørgsler i denne blog. I denne næste del vil vi diskutere endnu flere faktorer, som kan hjælpe dig med at maksimere ydeevnen. Hold dig opdateret!


  1. Fjerner duplikerede rækker fra tabellen i Oracle

  2. Hurtigste måde at importere stor CSV-fil til MySql ved hjælp af MySql CLI

  3. INSERT IGNORE vs INSERT ... PÅ DUBLIKAT NØGLOPDATERING

  4. hvordan tilføjer man brugerdefineret adapter til aktiviteten for at få listen til at blive vist i aktiviteten?