sql >> Databasteknik >  >> RDS >> MariaDB

Maximera databasfrågeeffektivitet för MySQL - del ett

Långsamma sökningar, ineffektiva sökningar eller långa sökningar är problem som regelbundet plågar DBA:er. De är alltid överallt, men är en oundviklig del av livet för alla som ansvarar för att hantera en databas.

Dålig databasdesign kan påverka frågans effektivitet och dess prestanda. Bristande kunskap eller felaktig användning av funktionsanrop, lagrade procedurer eller rutiner kan också orsaka försämring av databasprestanda och kan till och med skada hela MySQL-databasklustret.

För en master-slav-replikering är en mycket vanlig orsak till dessa problem tabeller som saknar primära eller sekundära index. Detta orsakar slavfördröjning som kan pågå under mycket lång tid (i ett värre scenario).

I denna tvådelade serieblogg ger vi dig en repetitionskurs i hur du kan hantera maximeringen av dina databasfrågor i MySQL för att få bättre effektivitet och prestanda.

Lägg alltid till ett unikt index till ditt bord

Tabeller som inte har primära eller unika nycklar skapar vanligtvis stora problem när data blir större. När detta händer kan en enkel dataändring stoppa databasen. Avsaknad av korrekta index och en UPDATE- eller DELETE-sats har tillämpats på den specifika tabellen, kommer en fullständig tabellsökning att väljas som frågeplan av MySQL. Det kan orsaka hög disk I/O för läsning och skrivning och försämrar prestandan för din databas. Se ett exempel nedan:

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)

Medan en tabell med primärnyckel har en mycket bra frågeplan,

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ära eller unika nycklar tillhandahåller en viktig komponent för en tabellstruktur eftersom detta är mycket viktigt, särskilt när man utför underhåll på ett bord. Om du till exempel använder verktyg från Percona Toolkit (som pt-online-schema-change eller pt-table-sync) rekommenderar vi att du måste ha unika nycklar. Tänk på att PRIMARY KEY redan är en unik nyckel och en primärnyckel kan inte innehålla NULL-värden utan unik nyckel. Att tilldela ett NULL-värde till en primärnyckel kan orsaka ett fel som,

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

För slavnoder är det också vanligt att i vissa tillfällen den primära/unika nyckeln inte finns på tabellen, vilket därför är avvikelser i tabellstrukturen. Du kan använda mysqldiff för att uppnå detta eller så kan du mysqldump --no-data ... params och och köra en diff för att jämföra dess tabellstruktur och kontrollera om det finns någon avvikelse.

Skanna tabeller med dubbletter av index och tappade det sedan

Duplicerade index kan också orsaka prestandaförsämring, särskilt när tabellen innehåller ett stort antal poster. MySQL måste utföra flera försök för att optimera frågan och utför fler frågeplaner att kontrollera. Det inkluderar genomsökning av stor indexdistribution eller statistik och som lägger till prestandaoverhead eftersom det kan orsaka minneskonflikt eller högt I/O-minnesutnyttjande.

Försämring för frågor när dubbletter av index observeras i en tabell attribut också för att mätta buffertpoolen. Detta kan också påverka prestanda för MySQL när checkpointing rensar transaktionsloggarna till disken. Detta beror på bearbetningen och lagringen av ett oönskat index (vilket i själva verket är ett slöseri med utrymme i den specifika tabellytan i den tabellen). Observera att dubbletter av index också lagras i tabellutrymmet som också måste lagras i buffertpoolen.

Ta en titt på tabellen nedan som innehåller flera dubbletter av nycklar:

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)

och har en storlek på 2,3GiB

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

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

Låt oss släppa dubblettindexen och bygga om tabellen med en no-oper alter,

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 kunnat spara upp till ~59 % av den gamla storleken på bordsutrymmet, vilket är riktigt stort.

För att fastställa dubbletter av index kan du använda pt-duplicate-checker för att hantera jobbet åt dig.

Justera din buffertpool

För det här avsnittet syftar jag bara på InnoDB-lagringsmotorn.

Buffertpoolen är en viktig komponent i InnoDB-kärnutrymmet. Det är här InnoDB cachar tabell- och indexdata när de används. Det påskyndar bearbetningen eftersom ofta använda data lagras i minnet effektivt med hjälp av BTREE. Till exempel, om du har flera tabeller som består av>=100GiB och är mycket åtkomliga, föreslår vi att du delegerar ett snabbt flyktigt minne från en storlek på 128GiB och börjar tilldela buffertpoolen med 80% av det fysiska minnet. De 80 % måste övervakas effektivt. Du kan använda SHOW ENGINE INNODB STATUS \G eller så kan du utnyttja övervakningsprogramvara som ClusterControl som erbjuder en finkornig övervakning som inkluderar buffertpool och dess relevanta hälsomått. Ställ även in variabeln innodb_buffer_pool_instances i enlighet med detta. Du kan ställa in detta större än 8 (standard om innodb_buffer_pool_size>=1GiB), som 16, 24, 32 eller 64 eller högre om det behövs.

När du övervakar buffertpoolen måste du kontrollera den globala statusvariabeln Innodb_buffer_pool_pages_free som ger dig tankar om det finns ett behov av att justera buffertpoolen, eller kanske överväga om det också finns oönskade eller dubbletter av index som förbrukar buffert. SHOW ENGINE INNODB STATUS \G erbjuder också en mer detaljerad aspekt av buffertpoolsinformationen inklusive dess individuella buffertpool baserat på antalet innodb_buffer_pool_instances du har ställt in.

Använd FULLTEXT-index (men bara om tillämpligt)

Använda frågor som,

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

där kontext är en kolumn av strängtyp (char, varchar, text), är ett exempel på en superdålig fråga! Att dra ett stort innehåll av poster med ett filter som måste vara girigt slutar med en full tabellskanning, och det är bara galet. Överväg att använda FULLTEXT index. Ett FULLTEXT-index har en inverterad indexdesign. Inverterade index lagrar en lista med ord och för varje ord en lista med dokument som ordet förekommer i. För att stödja närhetssökning lagras även positionsinformation för varje ord, som en byteoffset.

För att använda FULLTEXT för att söka eller filtrera data, måste du använda kombinationen av MATCH() ...MOT syntax och inte som frågan ovan. Naturligtvis måste du ange att fältet ska vara ditt FULLTEXT-indexfält.

För att skapa ett FULLTEXT-index, specificera bara med FULLTEXT som ditt index. Se exemplet nedan:

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)

Även om användning av FULLTEXT-index kan ge fördelar när du söker efter ord i ett mycket stort sammanhang i en kolumn, skapar det också problem när det används felaktigt.

När du gör en FULLTEXT-sökning efter en stor tabell som ständigt nås (där ett antal klientförfrågningar söker efter olika, unika sökord) kan det vara mycket CPU-krävande.

Det finns även vissa tillfällen då FULLTEXT inte är tillämplig. Se detta externa blogginlägg. Även om jag inte har provat detta med 8.0, ser jag inga ändringar som är relevanta för detta. Vi föreslår att du inte använder FULLTEXT för att söka i en stordatamiljö, särskilt för tabeller med hög trafik. Försök annars att utnyttja andra tekniker som Apache Lucene, Apache Solr, tsearch2 eller Sphinx.

Undvik att använda NULL i kolumner

Kolumner som innehåller nollvärden är helt ok i MySQL. Men om du använder kolumner med nollvärden i ett index kan det påverka frågeprestanda eftersom optimeraren inte kan tillhandahålla rätt frågeplan på grund av dålig indexfördelning. Det finns dock vissa sätt att optimera frågor som involverar nollvärden, men givetvis om detta passar kraven. Kontrollera dokumentationen för MySQL om Null Optimization. Du kan också kolla det här externa inlägget som också är användbart.

Designa din schematopologi och din tabellstruktur effektivt

I viss utsträckning, normalisering av dina databastabeller från 1NF (First Normal Form) till 3NF (Third Normal Form) ger dig en viss fördel för frågeeffektiviteten eftersom normaliserade tabeller tenderar att undvika redundanta poster. En korrekt planering och design för dina tabeller är mycket viktigt eftersom det är så du hämtade eller drar data och i var och en av dessa åtgärder har en kostnad. Med normaliserade tabeller är målet med databasen att säkerställa att varje icke-nyckelkolumn i varje tabell är direkt beroende av nyckeln; hela nyckeln och inget annat än nyckeln. Om detta mål uppnås betalar det av fördelarna i form av minskade uppsägningar, färre anomalier och förbättrad effektivitet.

Medan att normalisera dina tabeller har många fördelar, betyder det inte att du behöver normalisera alla dina tabeller på det här sättet. Du kan implementera en design för din databas med hjälp av Star Schema. Att designa dina tabeller med Star Schema har fördelen av enklare frågor (undvik komplexa korskopplingar), lätt att hämta data för rapportering, ger prestandavinster eftersom det inte finns något behov av att använda fackföreningar eller komplexa kopplingar, eller snabba aggregering. Ett stjärnschema är enkelt att implementera, men du måste planera noggrant eftersom det kan skapa stora problem och nackdelar när ditt bord blir större och kräver underhåll. Star Schema (och dess underliggande tabeller) är benägna att problem med dataintegritet, så du kan ha en hög sannolikhet att en massa av dina data är överflödiga. Om du tror att den här tabellen måste vara konstant (struktur och design) och är utformad för att utnyttja frågeeffektivitet, så är det ett idealiskt fall för detta tillvägagångssätt.

Att blanda dina databasdesigner (så länge du kan avgöra och identifiera vilken typ av data som ska hämtas på dina tabeller) är mycket viktigt eftersom du kan dra nytta av mer effektiva frågor och hjälpa DBA med säkerhetskopiering, underhåll och återställning.

Bli av med konstant och gammal data

Vi skrev nyligen några bästa metoder för att arkivera din databas i molnet. Den tar upp hur du kan dra nytta av dataarkivering innan den går till molnet. Så hur hjälper det att bli av med gammal data eller arkivera din konstanta och gamla data effektiviteten i fråga? Som det stod i min förra blogg så finns det fördelar med större tabeller som ständigt modifieras och infogas med ny data, tabellutrymmet kan växa snabbt. MySQL och InnoDB fungerar effektivt när poster eller data gränsar till varandra och har betydelse för nästa rad i tabellen. Det betyder att om du inte har några gamla poster som inte längre behöver användas, behöver optimeraren inte inkludera det i statistiken, vilket ger ett mycket effektivare resultat. Vettigt, eller hur? Dessutom är frågeeffektivitet inte bara på applikationssidan, den måste också ta hänsyn till dess effektivitet när du utför en säkerhetskopiering och vid underhåll eller failover. Till exempel, om du har en dålig och lång fråga som kan påverka din underhållsperiod eller en failover, kan det vara ett problem.

Aktivera frågeloggning vid behov

Ställ alltid in din MySQL:s långsamma frågelogg i enlighet med dina anpassade behov. Om du använder Percona Server kan du dra fördel av deras utökade långsamma frågeloggning. Det låter dig definiera vissa variabler. Du kan filtrera typer av frågor i kombination som full_scan, full_join, tmp_table, etc. Du kan också diktera hastigheten för långsam frågeloggning genom variabel log_slow_rate_type och många andra.

Vikten av att aktivera frågeloggning i MySQL (som långsam fråga) är fördelaktigt för att inspektera dina frågor så att du kan optimera eller finjustera din MySQL genom att justera vissa variabler som passar dina krav. För att aktivera långsam frågelogg, se till att dessa variabler är inställda:

  • long_query_time - tilldela rätt värde för hur lång tid frågorna kan ta. Om frågorna tar mer än 10 sekunder (standard) kommer den att falla ner till den långsamma frågeloggfilen du tilldelade.
  • slow_query_log - för att aktivera den, ställ in den på 1.
  • slow_query_log_file - detta är målsökvägen för din långsamma frågeloggfil.

Den långsamma frågeloggen är mycket användbar för frågeanalys och diagnostisering av dåliga frågor som orsakar stall, slavförseningar, långvariga frågor, minnes- eller CPU-intensiva, eller till och med får servern att krascha. Om du använder pt-query-digest eller pt-index-usage, använd den långsamma frågeloggfilen som källmål för att rapportera dessa frågor lika.

Slutsats

Vi har diskuterat några sätt du kan använda för att maximera effektiviteten i databasfrågor i den här bloggen. I nästa del kommer vi att diskutera ännu fler faktorer som kan hjälpa dig att maximera prestanda. Håll utkik!


  1. Sammanfoga en sträng och ett nummer i MySQL

  2. Verkliga exempel, när man ska använda OUTER / CROSS APPLY i SQL

  3. DATEFROMPARTS() Exempel i SQL Server (T-SQL)

  4. Två partitionerande egenheter