De verschillen tussen goed geschreven SQL en niet zijn enorm, en bij productie op een veelgevraagde site veroorzaken ze ernstige repercussies in de prestaties en betrouwbaarheid van de service. In deze gids zal ik bespreken hoe snelle query's kunnen worden geschreven en welke factoren bijdragen aan het traag maken ervan.
Vandaag wordt er veel gesproken over Big Data en nieuwe technologieën. NoSQL en cloud-gebaseerde oplossingen zijn geweldig, maar veel populaire websoftware (zoals WordPress, phpBB, Drupal, VBulletin Forum-software, enz.) Werkt nog steeds op MySQL. Migratie naar deze nieuwere oplossingen is misschien niet zo eenvoudig als alleen het optimaliseren van de configuratie die u al hebt in de productie. Trouwens, de prestaties van MySQL zijn erg goed, vooral de Percona-versie.
Maak niet de algemene fout om steeds meer rekenkracht te gebruiken bij het verwerken van het probleem van langzame query's en hoge serverbelastingen, in plaats van de onderliggende onderliggende problemen daadwerkelijk aan te pakken. Het toevoegen van CPU power, SSD's of RAM is een vorm van optimalisatie als je wilt, maar daar zal ik het hier niet over hebben. Ook zonder een geoptimaliseerde site, terwijl je groeit met de hardware, zullen de problemen exponentieel toenemen. Het is dus geen solide langetermijnoplossing.
Goed zijn in SQL is altijd een onmisbare tool voor een webontwikkelaar, en met de oplossing die vaak zo eenvoudig is als alleen maar het toevoegen van een index of het enigszins aanpassen van de manier waarop de tabel wordt gebruikt, helpt het echt om te weten hoe u uw RDBMS goed kunt gebruiken. In dit geval richten we ons op een populaire open-source database die vaak wordt gebruikt in combinatie met PHP, en dat is MySQL.
Webontwikkelaars, Database Architects / DBA's en systeembeheerders die bekend zijn met MySQL. Als je MySQL niet als newbie kent, zal deze gids waarschijnlijk niet veel zin hebben, maar ik zal proberen het zo informatief mogelijk te houden voor nieuwkomers op MySQL.
Ik raad aan om de stappen in je eigen MySQL-database te proberen (maak eerst een back-up natuurlijk!). Als u geen database hebt om aan te werken, kunt u bijvoorbeeld database-schema's maken waar van toepassing.
Een back-up maken van MySQL is eenvoudig met de mysqldump
opdrachtregelprogramma:
bash $ mysqldump myTable> myTable-backup.sql
U kunt meer leren over mysqldump.
In het kort en in geen enkele volgorde van belangrijkheid spelen de volgende allemaal significante factoren in query- en serverprestaties:
Waar
clausule (en gebruik van interne MySQL-functies zoals ALS
en DATUM
bijvoorbeeld)Bestel door
We zullen al deze gebieden in deze gids bespreken. Als u dit nog niet gebruikt, installeert u Percona, dat een vervangende vervanger is voor MySQL die een serieuze prestatieverhoging tot gevolg zal hebben. Bekijk deze vergelijking om een benchmark van Percona versus MySQL te bekijken.
Indexen worden door MySQL gebruikt om snel rijen met specifieke kolomwaarden te vinden, bijvoorbeeld binnen een WAAR
. Zonder een index moet MySQL beginnen met de eerste rij en vervolgens de hele tabel doorlezen om de relevante rijen te vinden. Hoe groter de tafel, hoe meer dit kost.
Als de tabel een index voor de betreffende kolommen heeft, kan MySQL snel de positie bepalen waarnaar moet worden gezocht in het midden van het gegevensbestand zonder naar alle gegevens te hoeven kijken. Dit is veel sneller dan elke rij achter elkaar lezen.
Wanneer uw scripttaal verbinding maakt met de database en u persistente verbindingen hebt geconfigureerd, kan deze een bestaande verbinding opnieuw gebruiken zonder een nieuwe te hoeven maken. Dit is optimaal voor productiegebruik en moet worden ingeschakeld.
PHP-gebruikers kunnen meer lezen in de PHP-handleiding.
De snelste, meest effectieve manier die ik heb gevonden om dit te repareren is via het gebruik van een sleutelwaarde paar winkel zoals memcached
of Redis
.
Met memcache
u kunt uw query-inhoud eenvoudigweg cachen met het volgende, bijvoorbeeld:
"php verbinden ( 'localhost', 11211); $ cacheResult = $ cache-> get ('sleutelnaam'); if ($ cacheResult) // ... geen behoefte om $ result = $ cacheResult te ondervragen; else // ... voer uw vraag uit $ mysqli = mysqli ('p: localhost', 'gebruikersnaam', 'wachtwoord', 'tabel'); // prepend p: naar hostname voor persistancy $ sql = 'SELECT * FROM berichten LEFT JOIN userInfo using (UID) WHERE posts.post_type =' post '|| posts.post_type = 'artikel' ORDER BY kolom LIMIT 50 '; $ result = $ mysqli-> query ($ sql); $ memc-> set ('sleutelnaam', $ resultaat-> fetch_array (), MEMCACHE_COMPRESSED, 86400);
// Geef het $ cacheResult door aan template $ template-> assign ('posts', $ cacheResult);
?>"
Nu het voorbeeld LINKS DOE MEE
query wordt slechts een keer per 86.400 seconden (24 uur) uitgevoerd, waardoor er een enorme hoeveelheid lading van de MySQL-server wordt verwijderd en de gelijktijdige verbindingen worden beperkt.
Opmerking: Prepend p:
naar uw host-argument in MySQLi voor permanente verbindingen.
Wanneer uw gegevens te groot worden of de vraag naar uw service omhoog gaat, kan paniek optreden. Een snelle oplossing om ervoor te zorgen dat uw service online blijft, kan schokken. Maar dat raad ik niet aan, omdat sharding inherent gegevensstructuren overdreven ingewikkeld lijkt te maken. En zoals heel welsprekend uitgelegd in dit artikel van de Percona-blog, niet scherven.
Het maken van databaseschema's is niet zo moeilijk als je enkele gouden regels accepteert, zoals werken met de beperkingen en je bewust zijn van wat efficiënt zal zijn. Het opslaan van afbeeldingen in de database als bobbel
datatypes zijn bijvoorbeeld sterk ontmoedigd; het opslaan van een bestandsnaam in a varchar
kolom datatype is veel beter.
Ervoor zorgen dat het ontwerp correct is voor het vereiste gebruik is van cruciaal belang bij het maken van uw app. Houd specifieke gegevens gescheiden (bijvoorbeeld categorieën en berichten) en zorg ervoor dat veel-op-één of één-op-veel relaties eenvoudig kunnen worden gekoppeld aan ID's. Gebruik maken van de VREEMDE SLEUTEL
faciliteit van MySQL is ideaal voor het cascaderen van data-contingentie tussen tabellen.
Probeer het volgende te onthouden bij het bouwen van uw tafel:
BESTELLING DOOR
in MySQL.UNIEK
index type voor unieke datasets en gebruik OP DUPLICATE SLEUTEL UPDATE
om een datetime of unix timestamp bij te werken, bijvoorbeeld van de laatste keer dat de rij werd gecontroleerd.INT
datatype voor integer numericals. Als u de lengte niet opgeeft, berekent MySQL zelf wat nodig is.Om effectief te optimaliseren, moeten we naar drie fundamentele gegevenssets met betrekking tot uw toepassing kijken:
Analyse kan op verschillende manieren worden gedaan. Eerst zullen we de meest directe route nemen om onder de motorkap van MySQL-query's te kijken. Het eerste hulpmiddel in uw optimalisatietoolbox is LEG UIT
. Gebruik dit in uw vraag voorafgaand aan de SELECT
geeft je de volgende output:
sql mysql> EXPLAIN SELECT * FROM 'wp_posts' WHERE 'post_type' = 'post'; + ---- + ------------- + ---------- + ------ + ------------ ------ + ------------------ + --------- + ------- + ------ + ------------- + | id | select_type | tafel | type | mogelijke_sleutels | sleutel | key_len | ref | rijen | Extra | + ---- + ------------- + ---------- + ------ + ------------ ------ + ------------------ + --------- + ------- + ------ + ------------- + | 1 | EENVOUDIG | wp_posts | ref | type_status_datum | type_status_datum | 82 | const | 2 | Waar gebruiken | + ---- + ------------- + ---------- + ------ + ------------ ------ + ------------------ + --------- + ------- + ------ + ------------- + 1 rij in set (0.00 sec)
De weergegeven kolommen bevatten nuttige informatie over de query die wordt uitgevoerd. De kolommen waar je goed op moet letten zijn possible_keys
en Extra
.
possible_keys
geeft de indexen weer die de MySQL-engine beschikbaar heeft voor de query. Soms moet u een index forceren om ervoor te zorgen dat de query op de snelste manier wordt uitgevoerd.
De Extra
kolom geeft aan of een voorwaardelijk WAAR
of BESTELLING DOOR
was gebruikt. Het belangrijkste om op te merken is als Fileort gebruiken
komt naar voren. Bekijk het volgende voorbeeld:
sql EXPLAIN SELECT main_text FROM berichten WHERE user = 'myUsername' && status = '1' && (status_spam_user = 'no_spam' || (status_spam_user = 'neutral' && status_spam_system = 'neutral')) ORDER BY datum DESC LIMIT 6430, 10
Dit type query kan naar de schijf gaan vanwege de conditionele waar, wat gebeurt als we naar de LEG UIT
:
sql id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE posts ref index_user, index_status index_user 32 const 7800 Waar gebruiken; Gebruik van filesort
Dus deze query heeft de mogelijkheid om twee indexen te gebruiken en momenteel raakt het schijf vanwege de Gebruik van filesort
in de Extra
.
Wat Fileort gebruiken
aan het doen is hier gedefinieerd uit de MySQL-handleiding:
"MySQL moet een extra pass doen om erachter te komen hoe de rijen in gesorteerde volgorde kunnen worden opgehaald. De sortering wordt uitgevoerd door alle rijen te doorlopen op basis van het type join en de sorteersleutel en aanwijzer naar de rij op te slaan voor alle rijen die overeenkomen met de WHERE-component. De sleutels worden vervolgens gesorteerd en de rijen worden in gesorteerde volgorde opgehaald. "
Deze extra pas zal uw app vertragen en moet ten koste van alles worden vermeden. Nog een cruciaal Extra
resultaat om te vermijden is Tijdelijk gebruiken
, wat betekent dat MySQL een tijdelijke tabel voor de query moest maken. Uiteraard is dit een afschuwelijk gebruik van MySQL en moet koste wat het kost worden voorkomen, tenzij je vanwege de gegevensvereisten niet verder kunt optimaliseren. In dit geval moet de query worden opgeslagen in Redis of Memcache en niet worden uitgevoerd door de gebruikers.
Om het probleem op te lossen Fileort gebruiken
we moeten ervoor zorgen dat MySQL een INHOUDSOPGAVE
. Het heeft verschillende possible_keys
om uit te kiezen, maar MySQL kan maar één index gebruiken in de laatste query. Hoewel de indexen composieten van verschillende kolommen kunnen zijn, is de inverse niet waar, hoewel u hints naar de MySQL-optimizer kunt geven over de indexen die u hebt gemaakt.
MySQL's optimizer gebruikt statistieken op basis van de querytabellen om de beste index voor het bereik van de query te selecteren. Dit gebeurt op basis van de statistische logica van de ingebouwde optimizer, hoewel dit met meerdere keuzes niet altijd zonder hints correct kan zijn. Gebruik de. Om ervoor te zorgen dat de juiste sleutel wordt gebruikt (of niet wordt gebruikt) FORCE INDEX
, GEBRUIK DE INDEX
en IGNORE INDEX
sleutelwoorden in uw vraag. U kunt meer lezen over indexhints in de MySQL-handleiding.
Gebruik de opdracht om naar de tabeltoetsen te kijken TOON INDEX
.
U kunt meerdere hints opgeven om de optimizer te gebruiken, bijvoorbeeld:
sql SELECT * FROM table1 USE INDEX (col1_index, col2_index) WHERE col1 = 1 AND col2 = 2 AND col3 = 3;
Running een LEG UIT
zal laten zien welke index werd gebruikt in het uiteindelijke resultaat. Dus om het vorige voorbeeld te herstellen, zullen we het toevoegen GEBRUIK DE INDEX
als zodanig:
sql EXPLAIN SELECT main_text FROM berichten USE INDEX (index_user) WHERE user = 'myUsername' && status = '1' && (status_spam_user = 'no_spam' || (status_spam_user = 'neutral' && status_spam_system = 'neutral')) ORDER BY datum DESC LIMIT 6430, 10
Nu heeft MySQL de index_status
van de te gebruiken tabel staat de vraag vast.
sql id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE posts ref index_user, index_status index_user 32 const 7800 Gebruik waar
naast LEG UIT
is de BESCHRIJVEN
trefwoord. Met BESCHRIJVEN
u kunt de informatie van een tabel als volgt bekijken:
sql mysql> DESCRIBE City; + ------------ + ---------- + ------ + ----- + --------- + - -------------- + | Veld | Type | Null | Sleutel | Standaard | Extra | + ------------ + ---------- + ------ + ----- + --------- + - -------------- + | Id | int (11) | NEE | PRI | NULL | auto_increment | | Naam | char (35) | NEE | | | | | Land | char (3) | NEE | UNI | | | | District | char (20) | JA | MUL | | | | Bevolking | int (11) | NEE | | 0 | | +------------+----------+------+-----+---------+----------------+
U maakt indexen in MySQL met de CREËER DE INDEX
syntaxis. Er zijn een paar smaken van de index. HELE TEKST
wordt gebruikt voor het zoeken naar volledige tekst, en dan is er de UNIEK
type om ervoor te zorgen dat gegevens uniek worden gehouden.
Als u een index aan uw tabel wilt toevoegen, gebruikt u de volgende syntaxis bijvoorbeeld:
sql mysql> CREATE INDEX idx_start_of_username AAN 'gebruikers' (gebruikersnaam (10));
Hiermee wordt een index op de tafel gemaakt gebruikers
, waarbij de eerste 10 letters van de gebruikersnaamkolom worden gebruikt, wat een varchar-gegevenstype is.
In dit geval moet elke lookups die een WAAR
sorteer op de gebruikersnaam en de match in de eerste 10 karakters zou hetzelfde zijn als een opzoeking van de hele tabel.
Indices hebben een enorm effect op de snelheid waarmee de querygegevens worden geretourneerd. Het instellen van een primaire sleutel en een unieke index is over het algemeen niet genoeg - samengestelde sleutels zijn waar de echte tuningsnis in MySQL ligt, en meestal vereist dit enige A / B-controle met LEG UIT
.
Als we bijvoorbeeld naar twee kolommen in onze kolom moeten verwijzen WAAR
Voorwaardelijk, een samengestelde sleutel zou ideaal zijn.
sql mysql> CREATE INDEX idx_composite AAN gebruikers (gebruikersnaam, actief);
Hier wordt deze sleutel gemaakt op de gebruikersnaam
kolom uit het vorige voorbeeld en de kolom actief
, een ENUM
gegevenstype dat aangeeft of het gebruikersaccount actief is. Dus nu bij het bevragen van de gegevens voor WAAR
de gebruikersnaam is geldig en het account is actief = 1
, de dataset is nu geoptimaliseerd om hier beter mee om te gaan.
Schakel profilering in om uw MySQL-zoekopdrachten van naderbij te bekijken. Dit kan tijdens runtime via worden gedaan set profilering = 1
, en dan het uitvoeren van uw vraag en het bekijken van het resultaat van toon profielen
.
Met PDO is hier een codefragment dat precies dat doet:
"php $ db-> query ('set profiling = 1'); $ db-> query ('selecteer kop, body, tags van berichten'); $ rs = $ db-> query ('toon profielen'); $ db-> query ('set profiling = 0'); // Schakel profilering uit nadat de query is uitgevoerd
$ records = $ rs-> fetchAll (PDO :: FETCH_ASSOC); // Verkrijg de resultaten van profilering
$ errmsg = $ rs-> errorInfo () [2]; // Vang hier eventuele fouten op "
Als u geen PDO gebruikt, kunt u hetzelfde doen met mysqli
als zodanig:
"php $ db = nieuwe mysqli ($ host, $ gebruikersnaam, $ wachtwoord, $ dbname);
$ db-> query ('set profiling = 1'); $ db-> query ('selecteer kop, tekst, tags van berichten'); if ($ result = $ db-> query ("SHOW profiles", MYSQLI_USE_RESULT)) while ($ row = $ result-> fetch_row ()) var_dump ($ row); $ resultaat-> sluiten ();
if ($ result = $ db-> query ("show profile for query 1", MYSQLI_USE_RESULT)) while ($ row = $ result-> fetch_row ()) var_dump ($ row); $ resultaat-> sluiten ();
$ db-> query ('set profiling = 0'); "
Dit zal u de profileringsgegevens teruggeven, die de uitvoeringstijd in de tweede waarde van de associatieve array zullen omvatten:
php array (3) [0] => string (1) "1" [1] => string (10) "0.00024300" [2] => string (17) "selecteer kop, tekst, tags van berichten"
De zoekopdracht duurde 0,00024300 seconden om te voltooien. Dat is snel genoeg om je geen zorgen over te maken. Maar als de cijfers stijgen, moeten we een diepere blik werpen.
Leer als een werkend voorbeeld je app kennen. Plaats een vinkje voor een DEBUG
constant in de database van uw applicatie database abstractie / kaders database en dan kunt u beginnen met auditing door een profielcase in te schakelen en het resultaat met een var_dump
/ print_r
. Nu kunt u met gemak door de pagina's van uw website bladeren en ze profileren!
Schakel Logging in om een volledige audit van uw zoekopdrachten uit te voeren. Sommige ontwikkelaars met wie ik heb gewerkt, zijn bang dat dit een dubbelzijdig probleem is, omdat het in staat stellen van het loggen de prestaties enigszins beïnvloedt, en dus zullen de statistieken die je opneemt iets lager zijn dan in werkelijkheid. Hoewel dit klopt, laten veel benchmarks zien dat het niet echt een verschil is.
Om het inloggen in MySQL versie 5.1.6 in te schakelen, gebruikt u de globale log_slow_queries
en kan een bestand opgeven met slow_query_log_file
globaal. Dit kan gedaan worden in de runtime prompt als zo:
bash set global log_slow_queries = 1; stel global in slow_query_log_file = /dev/slow_query.log;
U kunt dit permanent instellen in de /etc/my.cnf
of my.ini
configuratiebestand voor uw server.
bash log_slow_queries = 1; slow_query_log_file = /dev/slow_query.log;
Nadat u deze wijziging hebt aangebracht, moet u de MySQL-server opnieuw opstarten, bijvoorbeeld. service mysql opnieuw opstarten
op Linux-systemen.
In de nieuwere MySQL 5.6.1, log_slow_queries
is verouderd en slow_query_log
wordt in plaats daarvan gebruikt. inschakelen TAFEL
als output type zorgt voor een veel leukere debugging-ervaring en kan als volgt worden gedaan in MySQL 5.6.1 en later:
bash log_output = TABLE; log_queries_not_using_indexes = 1; long_query_time = 1
long_query_time
geeft het aantal seconden aan dat een langzame query als geclassificeerd is. De standaardwaarde is 10 en de minimumwaarde 0. Het kan milliseconde waarden zijn door een float op te geven; hier heb ik het ingesteld op 1 seconde. Dus elke zoekopdracht die langer dan 1 seconde duurt, wordt ingelogd in de TAFEL
uitvoerformaat.
Dit logt in op de mysql.slow_log
en mysql.general_log
tafels binnen MySQL
.
Schakel in om logboekregistratie uit te schakelen log_output
naar GEEN
.
log_queries_not_using_indexes
is een nuttige boolean die, wanneer ingeschakeld in combinatie met het trage querylogboek, betekent dat alleen query's die naar verwachting alle rijen ophalen, worden vastgelegd.
Deze optie betekent niet altijd dat er geen index wordt gebruikt. Als een query bijvoorbeeld een scan met volledige index gebruikt, wordt dit vastgelegd omdat de index het aantal rijen niet zou beperken.
Logboekregistratie op een productielocatie met verkeer inschakelen zal vrijwel altijd voor een korte periode moeten plaatsvinden, terwijl de belasting moet worden bewaakt om ervoor te zorgen dat deze niet van invloed is op de service. Als u zwaar wordt belast en een dringende oplossing nodig hebt, begin dan met het aanpakken van het probleem bij de prompt met TON PROCESSLIST
of via de information_schema.PROCESSLIST
tabel direct, bijv. selecteer * uit information_schema.PROCESSLIST;
.
Het vastleggen van alle query's in de productie kan u veel vertellen en is een goede gewoonte voor onderzoeksdoeleinden wanneer u een project controleert, maar als u het dagen achter elkaar laat draaien, krijgt u vaak geen bruikbare gegevens meer dan maximaal 48 uur zou doen ( neem gemiddeld de piektijden van het gebruik op, zodat u de zoekopdrachten goed kunt bekijken en ideeën voor de frequentie kunt opdoen).
Opmerking: als u een site beheert die piekspiegelingen ervaart en vervolgens periodes van niet veel (zoals een sportwebsite tijdens het seizoen tijdens en buiten het seizoen), wees dan logisch met hoe u naar logboeken kijkt. Ga er niet vanuit dat de site snel werkt. Voer een audit uit en vooral wat grafische weergave.
Percona heeft een aantal geweldige tools meegeleverd, en pt-query verteren
is een opdrachtregelprogramma voor het analyseren van querylogboeken, de proceslijst of tcpdumps.
Je kunt gebruiken pt-query verteren
op de volgende manieren:
Analyseer een * .log-bestand (bijvoorbeeld uitgevoerd door uw trage query-logboekregistratie):
bash $ pt-query-digest slow.log
Rapporteer de langzaamste query's van host1 in realtime (erg handig!):
bash $ pt-query-digest - processlist h = host1
Gebruik tcpdump om de langzaamste query's uit MySQL-protocolgegevens te melden:
"bash $ tcpdump -s 65535 -x -nn -q -tttt -i any -c 1000 port 3306> mysql.tcp.txt
$ pt-query-digest -type tcpdump mysql.tcp.txt "
Ten slotte kunnen we langzame querygegevens van de ene host naar een andere opslaan om later te kunnen beoordelen. Hier bewaren we de query-samenvatting voor slow.log naar host2:
bash $ pt-query-digest - review h = host2 - no-report slow.log
Om te leren hoe je de pt-query verteren
gereedschap van Percona, lees de handleiding.
Deze grafiek van InnoDB Row Operations toont de rijbewerkingen die InnoDB heeft uitgevoerd: updates, reads, deletes en inserts.
Dit is inderdaad een groot onderwerp en ik zal het in deze gids genoeg bespreken om u op weg te helpen met MySQL-monitoring. Het is echter belangrijk om in het algemeen op te merken dat het controleren van al uw website-services ideaal is om echt te weten wat uw prestaties en gebruik zijn..
Om dit te bereiken, raad ik aan om een RRDtool
-gebaseerde oplossing zoals cactussen
met een MySQL-configuratie. Koop een sjabloon voor Cacti van de jongens van Percona.
Zodra je Cacti hebt ingesteld en je app kunt analyseren, moet je wat tijd doorgeven zodat de grafieken kunnen worden opgebouwd. Na een paar dagen begint u de dag en nachtritmes van uw verkeer te zien en ziet u hoe druk de server echt wordt.
Als u op zoek bent naar automatische waarschuwingen en triggers, kunt u kijken naar de configuratie van monit, een open-source proactieve monitor voor Unix-systemen. Met monit kunt u regels voor uw server maken en ervoor zorgen dat u wordt gewaarschuwd wanneer de belasting stijgt, zodat u deze kunt vangen terwijl het gebeurt.
Het loggen van alle langzame query's die meer dan een seconde in beslag nemen, kan ons iets vertellen, maar ook weten welke zoekopdrachten honderden keren worden uitgevoerd, is even belangrijk. Zelfs als die query's te kort zijn om uit te voeren, eist de overhead van hoge aanvragen nog steeds zijn tol op de server.
Daarom is rondhangen wanneer je iets bijwerkt en live zet de meest cruciale tijd voor elk nieuw databasewerk en wijzigingen. We hebben altijd een beleid voor mijn teams om nooit wijzigingen in functiedatabases na een woensdag in een live project te synchroniseren. Het moet aan het begin van de week, uiterlijk dinsdag, worden gedaan, zodat alle teams hierop kunnen volgen en ondersteuning kunnen bieden.
Voordat u live gaat met nieuwe query's, moet u benchmarken met een loadtest-tool zoals ab
. Wanneer u de benchmark uitvoert, moet u de TON PROCESSLIST
, en ook logboekregistratie mogelijk maken en worden bewaakt met systeemhulpprogramma's zoals top
, gratis
en iostat
. Dit is een cruciale stap voordat u een nieuwe query in een live productie plaatst. Maar het is geen 100% zure test omdat live verkeer zich heel anders kan gedragen dan een berekende benchmark.
Benchmarken met ab
, zorg ervoor dat het pakket is geïnstalleerd, bijvoorbeeld:
bash #centos gebruikers $ sudo yum install ab #debian / ubuntu gebruikers $ sudo apt-get install ab
U kunt nu beginnen met het testen van uw app, bijvoorbeeld:
bash $ ab -k -c 350 -n 20000 mijn-domein.nl
De -k
bedoelt ermee in leven houden
de verbinding en de -c 350
is het aantal gelijktijdige verbindingen, dat wil zeggen het aantal mensen / klanten dat de site tegelijk zal raken. Eindelijk, de -n 20000
is het aantal verzoeken dat wordt gedaan my-domain.com
.
Dus door het bovenstaande commando uit te voeren, raak je http://my-domain.com/ met 350 gelijktijdige verbindingen tot er 20.000 verzoeken zijn voldaan, en dit zal gedaan worden met behulp van de keep alive header.
Nadat het proces de 20.000 verzoeken heeft voltooid, ontvangt u feedback over statistieken. Dit zal je vertellen hoe goed de site presteerde onder de stress die je zegt bij het gebruik van de bovenstaande parameters. Dit is een goede manier om automatisch te weten of uw zoekopdracht iets heeft veranderd.
Verzoekhoeveelheid en serverbelasting hebben een enorme invloed op de prestaties en daardoor kan de querytijd hierdoor worden beïnvloed. In alles zou u het trage querylog moeten inschakelen om dit in productie te vangen en in de regel moet u ervoor zorgen dat alle query's worden uitgevoerd in breuken van een milliseconde (0,0xx of sneller) op een inactieve server.
Implementeren memcache
heeft een dramatische impact op uw belastingsvereisten en zal worden gebruikt om resources die werden gebruikt voor het verwerken van query's serieus te ontladen. Zorg ervoor dat je gebruikt memcached
effectief en benchmark uw app met een warme cache (vooraf geladen met waarden) versus een koude.
Om te voorkomen dat u met een lege cache de productie in gaat, is een pre-loader-script een goede manier om ervoor te zorgen dat de cache wordt gelezen en krijgt u niet een groot aantal verzoeken tegelijk binnen wanneer u terugkeert van een downtime vanwege faalfactoren voor overcapaciteit.
Dus nadat u logboekregistratie heeft ingeschakeld, heeft u nu enkele langzame query's in uw app gevonden. Laten we ze repareren! Ik zal bijvoorbeeld verschillende veelvoorkomende problemen demonstreren die u tegen zult komen en de logica om ze op te lossen.
Als u nog geen trage query's hebt gevonden, controleert u misschien wat uw instellingen waren voor de long_query_time
als u de methode voor het loggen van query's gebruikt. Anders heeft u al uw vragen gecontroleerd met profilering (set profilering = 1
), maak een lijst van de vragen die langer duren dan een fractie van een milliseconde om te voltooien (0.000x seconden) en laten we beginnen met die.
Hier zijn zes veelvoorkomende problemen die ik tegenkom bij het optimaliseren van MySQL-query's:
BESTELLING DOOR
gebruikend filesort.sql mysql> selecteer select * uit producten waar products.price> 4 en products.stock> 0 op naam staan; + ---- + ------------- + ---------- + ------ + ------------ --- + ------ + --------- + ------ + ------ + --------------- -------------- + | id | select_type | tafel | type | mogelijke_sleutels | sleutel | key_len | ref | rijen | Extra | + ---- + ------------- + ---------- + ------ + ------------ --- + ------ + --------- + ------ + ------ + --------------- -------------- + | 1 | EENVOUDIG | producten | ALL | NULL | NULL | NULL | NULL | 1142 | Waar gebruiken; Gebruik van filesort | +----+-------------+----------+------+---------------+------+---------+------+------+-----------------------------+
Het vermijden van filesort is onmogelijk vanwege de BESTELLING OP naam
. Ongeacht welke indexpermutatie u gebruikt, het beste dat u krijgt, is Waar gebruiken; Fileort gebruiken
in uw Extra
kolom. Om dit te optimaliseren slaat u het resultaat op in Memcache of doet u bestelt in de logische laag van uw toepassing.
BESTELLING DOOR
op WAAR
en een LINKS DOE MEE
BESTELLING DOOR
heeft een aanzienlijke tol op zoekopdrachten. Het volgende is bijvoorbeeld een standaard LINKS DOE MEE
van a producten
tafel en categorieën
tabel door middel van een integer ID. Wanneer het bestellen is verwijderd, wordt het bestandendashot ook verwijderd.
"sql mysql> uitleg over geselecteerde producten. * uit producten gebruik index (idx_price) linkse join-categorieën met behulp van (catID) waar products.price> 4 en catID = 4 BESTELLING PER voorraad ASC-limiet 10; + - + - + - + - - + - + - + - + - + - + - + | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | + - + - + - + - + - + - + - + - + - + - + | 1 | SIMPLE | producten | ALL | idx_price | NULL | NULL | NULL | 986 | Waar gebruiken; Filesort gebruiken | | 1 | EENVOUD | categorieën | const | PRIMAIR | PRIMAIR | 4 | const | 1 | Index + - + - + - + - + - + - + - + - + - + - + 2 rijen in set gebruiken (0.00 sec)
mysql> geef een toelichting op bepaalde producten * van producten gebruik index (idx_price) linkse join-categorieën met behulp van (catID) waar products.price> 4 en catID = 4; + - + - + - + - + - + - + - + - + - + - + | id | select_type | tafel | type | mogelijke_sleutels | sleutel | key_len | ref | rijen | Extra | + - + - + - + - + - + - + - + - + - + - + | 1 | EENVOUDIG | producten | ALL