{"id":21010,"date":"2026-08-26T08:33:40","date_gmt":"2026-08-26T06:33:40","guid":{"rendered":"https:\/\/webhosting.de\/mysql-explain-analyze-abfragen-interpretieren-query-tuning\/"},"modified":"2026-08-26T08:33:40","modified_gmt":"2026-08-26T06:33:40","slug":"mysql-explain-analyze-fortolkning-af-foresporgsler-optimering-af-foresporgsler","status":"publish","type":"post","link":"https:\/\/webhosting.de\/da\/mysql-explain-analyze-abfragen-interpretieren-query-tuning\/","title":{"rendered":"MySQL EXPLAIN ANALYZE: Korrekt fortolkning af foresp\u00f8rgsler for optimal ydeevne"},"content":{"rendered":"<p>Med `mysql explain` analyserer jeg, hvordan MySQL 8 udarbejder en plan <strong>udf\u00f8rer<\/strong> og hvilke trin der tager en m\u00e5lbar tid. P\u00e5 den m\u00e5de kan jeg ud fra de faktiske k\u00f8retider, antallet af linjer og l\u00f8kker se, hvor jeg skal justere en plan og <strong>Ydelse<\/strong> m\u00e5lrettet \u00f8ge antallet af mine s\u00f8gninger.<\/p>\n\n<h2>Centrale punkter<\/h2>\n\n<p>For at du straks kan komme til sagens kerne, vil jeg kort opsummere de vigtigste l\u00e6ringsm\u00e5l og angive de relevante <strong>Prioriteringer<\/strong>. Hver linje i planen fort\u00e6ller en historie, og jeg viser dig, hvad du virkelig <strong>respekterede<\/strong>. L\u00e6s punkterne, gennemg\u00e5 dine foresp\u00f8rgsler og oms\u00e6t indsigterne direkte til optimeringstiltag.<\/p>\n<ul>\n  <li><strong>Faktiske l\u00f8betider<\/strong>: EXPLAIN ANALYZE udf\u00f8rer foresp\u00f8rgslen og m\u00e5ler tiden for hvert trin.<\/li>\n  <li><strong>Sk\u00f8n vs. virkelighed<\/strong>: Store afvigelser tyder p\u00e5 fejl i statistikkerne eller manglende indekser.<\/li>\n  <li><strong>TREE-format<\/strong>: Planen som et tr\u00e6 g\u00f8r iteratorer, filtre og sammenf\u00f8jninger synlige.<\/li>\n  <li><strong>Hotspots<\/strong>: Lange \u201etime to last row\u201c-v\u00e6rdier og mange loop markerer tuningm\u00e5lene.<\/li>\n  <li><strong>Indeksstrategi<\/strong>: Passende (ogs\u00e5 sammensatte) indekser s\u00e6nker omkostningerne markant.<\/li>\n<\/ul>\n<p>Listen giver dig et klart <strong>retning<\/strong>, men det er f\u00f8rst, n\u00e5r du rent praktisk l\u00e6ser planen, at du kan udnytte denne viden til din fordel. Umiddelbart derefter viser jeg, hvordan jeg vurderer hvert n\u00f8gletal, og hvilke n\u00e6ste <strong>Trin<\/strong> som jeg udleder heraf.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img fetchpriority=\"high\" decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/08\/mysql-analyse-buero-8723.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>EXPLAIN vs. EXPLAIN ANALYZE: Hvad jeg egentlig m\u00e5ler<\/h2>\n\n<p>Med klassisk EXPLAIN kan jeg se optimeringsprogrammets planlagte forl\u00f8b, alts\u00e5 en <strong>Udkast<\/strong> med ansl\u00e5ede omkostninger og antal linjer. Denne plan afsl\u00f8rer r\u00e6kkef\u00f8lgen af tabellerne, de anvendte indekser og sammenk\u00e6dningsstrategien, dog uden egentlig <strong>M\u00e5lte v\u00e6rdier<\/strong>. EXPLAIN ANALYZE forts\u00e6tter og udf\u00f8rer faktisk foresp\u00f8rgslen, m\u00e5ler tiden indtil den f\u00f8rste og sidste r\u00e6kke samt antallet af l\u00f8kker. P\u00e5 den m\u00e5de kan jeg straks se, hvilken node i tr\u00e6et der tager mest tid, og hvor jeg skal s\u00e6tte ind. S\u00e5ledes erstatter jeg gisninger med m\u00e5lte <strong>Data<\/strong> og tr\u00e6ffe velunderbyggede beslutninger om optimering.<\/p>\n\n<h2>Syntaks og typiske anvendelsestilf\u00e6lde<\/h2>\n\n<p>Jeg starter analysen med en simpel kommando: <code>EXPLAIN ANALYZE SELECT ...<\/code>, fordi jeg dermed umiddelbart <strong>L\u00f8betider<\/strong> pr. node. Udskriften i TREE-format viser iteratorer som scanninger, sammenf\u00f8jninger, sorteringer og filtre med estimerede og faktiske <strong>Linjer<\/strong>. Jeg bruger det is\u00e6r til gentagne problemforesp\u00f8rgsler, UPDATE\/DELETE p\u00e5 flere tabeller og til s\u00e6tninger med ORDER BY eller GROUP BY. Som et ekstra hj\u00e6lpemiddel bruger jeg <code>FORMAT=JSON<\/code>, hvis jeg vil dykke dybt ned i omkostningsmodellen, men til finjustering i hverdagen er tr\u00e6et som regel nok. Den, der \u00f8nsker at g\u00e5 mere i dybden med optimeringssp\u00f8rgsm\u00e5l, kan finde gode ideer i <a href=\"https:\/\/webhosting.de\/da\/mysql-optimizer-query-hosting-optimering-serverboost\/\">Optimizer-detaljer<\/a>, som jeg bruger i praksis.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/08\/mysql_meeting_9245.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>S\u00e5dan l\u00e6ser jeg TREE-planen<\/h2>\n\n<p>Jeg betragter hver knude som et selvst\u00e6ndigt trin, der genererer data eller <strong>filtrerer<\/strong>. Scanninger leverer r\u00e6kker fra tabeller eller indekser, sammenkoblinger forbinder datastr\u00f8mme, filtre reducerer antallet af r\u00e6kker, og sorteringer ordner eller grupperer de <strong>Resultater<\/strong>. Felterne \u201erows (actual\/estimated)\u201c, \u201etime to first row\u201c, \u201etime to last row\u201c og \u201eloops\u201c er mine vigtigste pejlem\u00e6rker. Hvis det faktiske antal r\u00e6kker afviger markant fra estimatet, korrigerer jeg statistikker eller indekser. Hvis \u201etime to last row\u201c tr\u00e6kker ekstremt ud, tjekker jeg sene sorteringer, store sammenf\u00f8jninger eller uhensigtsm\u00e6ssige <strong>Filtre<\/strong>.<\/p>\n\n<h2>At forst\u00e5 n\u00f8gletal: Fra sk\u00f8n til virkelighed<\/h2>\n\n<p>Jeg har samlet de vigtigste n\u00f8gletal i en overskuelig tabel, s\u00e5 du hurtigt kan se de typiske signaler <strong>genkende<\/strong>. Hver linje viser dig, hvad en m\u00e5ling betyder, hvilket advarselstegn jeg observerer, og hvilken foranstaltning der oftest <strong>Hj\u00e6lper<\/strong>.<\/p>\n\n<table>\n  <thead>\n    <tr>\n      <th>N\u00f8gletal<\/th>\n      <th>Betydning<\/th>\n      <th>advarselssignal<\/th>\n      <th>Tuning-tilgang<\/th>\n    <\/tr>\n  <\/thead>\n  <tbody>\n    <tr>\n      <td>r\u00e6kker (est.\/akt.)<\/td>\n      <td>Planlagt vs. faktisk <strong>Linjer<\/strong><\/td>\n      <td>Stor afvigelse (f.eks. 10 mod 100.000)<\/td>\n      <td>Opdatere statistikker, manglende <strong>Indekser<\/strong> Tjek<\/td>\n    <\/tr>\n    <tr>\n      <td>tid til f\u00f8rste r\u00e6kke<\/td>\n      <td>Tid indtil den f\u00f8rste <strong>Udgave<\/strong><\/td>\n      <td>Langsomt p\u00e5 trods af et lille antal resultater<\/td>\n      <td>Kontroller startknudepunktet, tidlige filtre <strong>styrke<\/strong><\/td>\n    <\/tr>\n    <tr>\n      <td>tid til sidste r\u00e6kke<\/td>\n      <td>Samlet varighed af <strong>Knudepunkter<\/strong><\/td>\n      <td>Betydeligt h\u00f8jere end \u201efirst row\u201c<\/td>\n      <td>Sortering, sammenkoblingsstrategi, str\u00f8mme <strong>reducere<\/strong><\/td>\n    <\/tr>\n    <tr>\n      <td>loops<\/td>\n      <td>Hyppigheden af <strong>Gentagelse<\/strong><\/td>\n      <td>Mange iterationer<\/td>\n      <td>Omstrukturering af JOIN'er, underforesp\u00f8rgsler <strong>omforme<\/strong><\/td>\n    <\/tr>\n  <\/tbody>\n<\/table>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/08\/mysql-explain-analyze-performance-8159.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Korrekt fortolkning af operatorer: scanninger, sammenkoblinger, sorteringer<\/h2>\n\n<p>Jeg l\u00e6gger m\u00e6rke til, hvilken <strong>Iterator<\/strong> faktisk udf\u00f8rer arbejdet:<\/p>\n<ul>\n  <li><strong>Indeksinterval\/unik scanning<\/strong>: Ideel ved selektive WHERE-betingelser og passende pr\u00e6fikser; \u201etime to first row\u201c er kort, \u201etime to last row\u201c afh\u00e6nger af resultats\u00e6ttet.<\/li>\n  <li><strong>Tabelgennemgang<\/strong>: Advarselssignal ved store tabeller; i s\u00e5 fald leder jeg efter egnede filtre, sammensatte indekser eller en omformulering af foresp\u00f8rgslen.<\/li>\n  <li><strong>Nested loop-sammenf\u00f8jning<\/strong>: Standardstrategi; mange \u201eloops\u201c tyder p\u00e5 en uegnet driver eller manglende indeks p\u00e5 den indre tabel.<\/li>\n  <li><strong>Hash-sammenf\u00f8jning<\/strong> (MySQL 8): Velegnet til store, j\u00e6vnt fordelte Equi-Joins. \u201eTime to first row\u201c kan v\u00e6re l\u00e6ngere (i opbygningsfasen), men \u201etime to last row\u201c forbedres, hvis pr\u00f8vestr\u00f8mmen er stor.<\/li>\n  <li><strong>Sorter<\/strong>\/<strong>Gruppe<\/strong>: Synlig som en separat node i TREE. Lange k\u00f8retider tyder ofte p\u00e5 manglende underst\u00f8ttelse via indekser.<\/li>\n  <li><strong>Filtre<\/strong>: Senere filtre indikerer forpassede muligheder for indeksbetinget pushdown eller tidligere selektion.<\/li>\n<\/ul>\n<p>Hvis en Sort-node dominerer \u201etime to last row\u201c, unders\u00f8ger jeg, om den \u00f8nskede r\u00e6kkef\u00f8lge kan opn\u00e5s via et indeks, f.eks. ved hj\u00e6lp af <strong>Covering<\/strong>-Indekser med passende sorteringsr\u00e6kkef\u00f8lge. Hvis ORDER BY-klausulen stemmer overens med indeksdefinitionen (retning, pr\u00e6fiks), kan sorteringstrinnet ofte helt udelades.<\/p>\n\n<h2>M\u00e5lemetode: S\u00e5dan sammenligner jeg p\u00e5 en retf\u00e6rdig m\u00e5de<\/h2>\n\n<p>Jeg m\u00e5ler ikke kun \u00e9n gang. Caching-effekter kan forvride indtrykket, derfor:<\/p>\n<ul>\n  <li>Jeg k\u00f8rer EXPLAIN ANALYZE flere gange og vurderer medianen og sp\u00e6ndvidden i stedet for en enkelt v\u00e6rdi.<\/li>\n  <li>Jeg skelner mellem \u201ekold\u201c og \u201evarm\u201c cache: Varme m\u00e5linger viser, hvad brugerne oplever efter den f\u00f8rste k\u00f8rsel.<\/li>\n  <li>Jeg varierer repr\u00e6sentative parametre, s\u00e5 planen ikke kun ser god ud i et trivielt eksempel.<\/li>\n  <li>Jeg dokumenterer skemaet og datastatus, s\u00e5 jeg senere kan spore resultaterne.<\/li>\n<\/ul>\n<p>Ved DML-s\u00e6tninger (UPDATE\/DELETE) bruger jeg en transaktion: <code>START TRANSACTION; EXPLAIN ANALYZE UPDATE ...; ROLLBACK;<\/code>. P\u00e5 den m\u00e5de f\u00e5r jeg reelle m\u00e5lev\u00e6rdier uden varige \u00e6ndringer. Vigtigt: EXPLAIN ANALYZE <strong>f\u00f8rer<\/strong> \u2013 derfor bruger jeg det med omtanke p\u00e5 produktionssystemerne.<\/p>\n\n<h2>Statistik og datadistribution: Afhj\u00e6lpning af sk\u00f8nfejl<\/h2>\n\n<p>Store forskelle mellem linjerne \u201eestimated\u201c og \u201eactual\u201c skyldes ofte sk\u00e6ve datafordelinger. I s\u00e5danne tilf\u00e6lde anvender jeg en tostrenget tilgang:<\/p>\n<ul>\n  <li><strong>Opdater statistikker<\/strong>: Jeg s\u00f8rger for, at optimeringsv\u00e6rkt\u00f8jet har aktuelle oplysninger. Opdaterede statistikker forbedrer valget af sammenk\u00e6dninger og indekser.<\/li>\n  <li><strong>Brug af histogrammer<\/strong>: Ved kolonner med stor sk\u00e6vhed hj\u00e6lper histogrammer med at estimere selektiviteterne mere realistisk. I EXPLAIN ANALYZE mindskes forskellen mellem estimatet og virkeligheden s\u00e5 m\u00e6rkbart.<\/li>\n<\/ul>\n<p>Hvis estimaterne fortsat er forkerte efter opdateringen, gennemg\u00e5r jeg sammensatte indekser i r\u00e6kkef\u00f8lge efter de mest selektive pr\u00e6dikater og ser p\u00e5 korrelationer mellem kolonnerne. M\u00e5let er, at s\u00e5 f\u00e5, godt forfiltrerede r\u00e6kker som muligt s\u00e5 tidligt som muligt indg\u00e5r i de dyre operatorer.<\/p>\n\n<h2>Semi-join-strategier og underforesp\u00f8rgsler<\/h2>\n\n<p>MySQL 8 omdanner ofte IN\/EXISTS-pr\u00e6dikater til semi-join-planer. I TREE ser jeg det som \u00bbMaterialization\u00ab, \u00bbFirstMatch\u00ab eller \u00bbLoose Index Scan\u00ab. Jeg er opm\u00e6rksom p\u00e5:<\/p>\n<ul>\n  <li><strong>Materialisering<\/strong>: En delm\u00e6ngde oprettes \u00e9n gang og genbruges flere gange \u2013 velegnet til moderat st\u00f8rrelse.<\/li>\n  <li><strong>FirstMatch<\/strong>: Stop tidligt ved det f\u00f8rste hit \u2013 det sparer loops, hvis der kun forventes f\u00e5 hits pr. ydre r\u00e6kke.<\/li>\n  <li><strong>L\u00f8s indeksscanning<\/strong>: Meget effektiv ved DISTINCT-lignende m\u00f8nstre via indekser.<\/li>\n<\/ul>\n<p>Underforesp\u00f8rgsler, der k\u00f8rer for hver r\u00e6kke i den ydre tabel, forl\u00e6nger \u201eloops\u201c. Jeg omdanner dem til JOIN\u2019er eller materialiserer dem bevidst (CTE\/Derived), s\u00e5 k\u00f8rselsplanen udf\u00f8rer det ressourcekr\u00e6vende arbejde \u00e9n gang og derefter henviser til resultatet p\u00e5 en mere effektiv m\u00e5de.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/08\/mysql_analyze_4892.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>M\u00e5lrettet SQL-optimering: trin for trin<\/h2>\n\n<p>Jeg starter med indeksstrategien og sikrer hyppige WHERE- og JOIN-betingelser med <strong>Indekser<\/strong> . Hvis jeg har brug for flere kolonner i filtrering eller sortering, opretter jeg sammensatte indekser og tilpasser kolonnernes r\u00e6kkef\u00f8lge efter de hyppigst forekommende <strong>Pr\u00e6dikater<\/strong>. Derefter optimerer jeg underforesp\u00f8rgsler, der k\u00f8rer i l\u00f8kker, ved at omformulere dem eller omdanne dem til sammenk\u00e6dninger. Jeg erstatter SELECT * med konkrete kolonner, s\u00e5 der flyttes f\u00e6rre data, og planen aflastes. Derefter holder jeg statistikkerne opdaterede, da un\u00f8jagtige sk\u00f8n leder optimeringsv\u00e6rkt\u00f8jet i den forkerte retning <strong>Afvigelser<\/strong>.<\/p>\n\n<h2>Indeks-praksis: D\u00e6kning, r\u00e6kkef\u00f8lge, eksperimenter<\/h2>\n\n<p>Jeg bruger tre enkle parametre, som straks bliver synlige i EXPLAIN ANALYZE:<\/p>\n<ul>\n  <li><strong>D\u00e6kkende indekser<\/strong>: Hvis indekset indeholder alle de n\u00f8dvendige kolonner (filter, sammenkobling, projektion), sparer planen for tabelopslag. \u201etime to last row\u201c falder ofte markant.<\/li>\n  <li><strong>R\u00e6kkef\u00f8lgen af kolonnerne<\/strong>: Jeg sorterer efter selektivitet og brugstype (filter f\u00f8r sortering). Til ORDER BY\/GROUP BY bruger jeg den korrekte retning og det passende pr\u00e6fiks.<\/li>\n  <li><strong>Indeksfors\u00f8g<\/strong>: Med midlertidige, <em>usynlige<\/em> Jeg tester indekser for at se, om optimeringsv\u00e6rkt\u00f8jet ville v\u00e6lge dem uden at forstyrre eksisterende planer. Hvis planen bliver bedre, aktiverer jeg indekset permanent.<\/li>\n<\/ul>\n<p>Hvis der findes flere kandidatindekser, sammenligner jeg planerne med EXPLAIN ANALYZE og m\u00e5ler konsekvent \u201etime to last row\u201c. I tvivlstilf\u00e6lde v\u00e6lges den plan, der har den mest stabile k\u00f8retid p\u00e5 tv\u00e6rs af forskellige parameterv\u00e6rdier.<\/p>\n\n<h2>Praktisk eksempel: L\u00e6se planen, oprette indeks, m\u00e5le succesen<\/h2>\n\n<p>Jeg tager et typisk sp\u00f8rgsm\u00e5l: <code>EXPLAIN ANALYZE SELECT o.id, o.date, c.name FROM orders o JOIN customers c ON c.id = o.customer_id WHERE o.date &gt;= '2025-01-01' ORDER BY o.date DESC;<\/code> og tjek f\u00f8rst knuden for tabellen <strong>ordrer<\/strong>. Hvis planen viser et stort antal faktiske r\u00e6kker og en fuld tabelscanning, opretter jeg en passende indeks, f.eks. p\u00e5 <code>orders(dato, kunde-id)<\/code>. Derefter sammenligner jeg \u201etime to last row\u201c f\u00f8r og efter \u00e6ndringen, fordi dette tal meget tydeligt viser den samlede effekt <strong>viser<\/strong>. Hvis ORDER BY stemmer overens med indeksr\u00e6kkef\u00f8lgen, sparer jeg mig for en sortering og reducerer den samlede varighed betydeligt. P\u00e5 den m\u00e5de dokumenterer jeg fremskridt med m\u00e5lte v\u00e6rdier i stedet for med vage <strong>Indtryk<\/strong>.<\/p>\n\n<h2>Sikker analyse af DML-s\u00e6tninger<\/h2>\n\n<p>N\u00e5r det g\u00e6lder UPDATE\/DELETE-kommandoer, der \u00e6ndrer datam\u00e6ngden, g\u00e5r jeg struktureret til v\u00e6rks:<\/p>\n<ul>\n  <li>Jeg indkapsler m\u00e5lingen i en transaktion og ruller den tilbage, hvis jeg blot vil foretage en m\u00e5ling.<\/li>\n  <li>Jeg unders\u00f8ger, om triggere\/begr\u00e6nsninger medf\u00f8rer ekstra omkostninger \u2013 EXPLAIN ANALYZE viser l\u00e6ngere k\u00f8retider i de ber\u00f8rte noder.<\/li>\n  <li>Jeg holder \u00f8je med forholdet mellem \u201eaffected rows\u201c og \u201erows actual\u201c \u2013 et d\u00e5rligt forhold tyder p\u00e5, at filtreringen sker for sent, eller at der mangler indekser.<\/li>\n<\/ul>\n<p>Ved UPDATE-s\u00e6t, der involverer flere tabeller, er r\u00e6kkef\u00f8lgen af sammenkoblinger og indeksd\u00e6kning afg\u00f8rende. Lange \u201etime to last row\u201c-tider ved sorterings-\/sammenkoblingsknudepunkter tyder p\u00e5, at der er potentiale for indeksforbedringer eller en omformulering til to m\u00e5lrettede s\u00e6tninger med mellemopbevaring.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/08\/mysql_explain_analyze_8374.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Hostingens indflydelse p\u00e5 foresp\u00f8rgselens ydeevne<\/h2>\n\n<p>Jeg betragter ikke databasen isoleret, for hukommelse, I\/O og CPU pr\u00e6ger hver <strong>Runtime<\/strong>. Hurtige SSD\u2019er forkorter ventetiden ved l\u00e6sning, tilstr\u00e6kkelig RAM udvider bufferpuljen, og en solid CPU-stack fremskynder sortering, aggregering og <strong>Tilslutter sig<\/strong>. I produktive milj\u00f8er foretr\u00e6kker jeg hosting-ops\u00e6tninger, der klarer datakr\u00e6vende arbejdsbelastninger godt. Jeg f\u00e5r ogs\u00e5 nyttig baggrundsviden om emner vedr\u00f8rende optimering fra <a href=\"https:\/\/webhosting.de\/da\/en-indgaende-forklaring-af-mariadbs-foresporgselsoptimerer-indsigt-i-sql-tuning\/\">Optimizer internt<\/a>, som jeg bruger som et supplerende perspektiv. N\u00e5r jeg kombinerer en velgennemt\u00e6nkt plan med et st\u00e6rkt milj\u00f8, opn\u00e5r jeg m\u00e6rkbare gevinster ved <strong>Svartider<\/strong>.<\/p>\n\n<h2>Ressourcer og operatorer i sammenh\u00e6ng<\/h2>\n\n<p>N\u00e5r jeg l\u00e6ser planen, l\u00e6gger jeg is\u00e6r m\u00e6rke til hukommelseskr\u00e6vende knudepunkter. Store sorteringer eller hash-joins kr\u00e6ver arbejdshukommelse; hvis de er for store, udf\u00f8res de i midlertidige tabeller. I TREE kan jeg se dette p\u00e5 sene, langsomme knudepunkter og en tydelig forskel mellem \u201etime to first row\u201c og \u201etime to last row\u201c. Jeg reagerer ved at:<\/p>\n<ul>\n  <li>Reduktion af indgangsdatam\u00e6ngden (tidligere filtre, bedre join-drivere).<\/li>\n  <li>Forbedret indeksst\u00f8tte til den \u00f8nskede r\u00e6kkef\u00f8lge for at undg\u00e5 sorter.<\/li>\n  <li>Kontroller, om sammenkoblingstypen (Nested Loop eller Hash) passer til datam\u00e6ngden.<\/li>\n<\/ul>\n<p>Is\u00e6r ved rapportk\u00f8rsler k\u00f8rer jeg EXPLAIN ANALYZE p\u00e5 repr\u00e6sentative data, ikke p\u00e5 mini-snapshots. F\u00f8rst da afspejler m\u00e5lev\u00e6rdierne den reelle belastning.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\">\n  <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/webhosting.de\/wp-content\/uploads\/2026\/08\/mysql-analyse-0912.png\" alt=\"\" width=\"1536\" height=\"1024\"\/>\n<\/figure>\n\n\n<h2>Gode r\u00e5d til hverdagen<\/h2>\n\n<p>F\u00f8rst analyserer jeg de foresp\u00f8rgsler, der springer i \u00f8jnene i logfilerne, eller som brugerne regelm\u00e6ssigt oplever som langsomme <strong>anmelde<\/strong>. Derefter foretager jeg m\u00e5linger med EXPLAIN ANALYZE, dokumenterer de vigtigste tal og sammenligner sk\u00f8n med de faktiske resultater. P\u00e5 dette grundlag \u00e6ndrer jeg m\u00e5lrettet indekser og formuleringer og noterer resultaterne f\u00f8r og efter, s\u00e5 fremskridtene kan spores <strong>lave<\/strong>. Jeg indplanl\u00e6gger disse analyser tidligt i udviklingsforl\u00f8bet i stedet for at vente p\u00e5, at der opst\u00e5r produktionsproblemer. Gennem gentagne gennemgange kan jeg hurtigere genkende m\u00f8nstre og tr\u00e6ffe mere sikre beslutninger om <strong>Indstilling<\/strong>-tiltag.<\/p>\n\n<h2>Pragmatisk tjekliste til hurtigere planer<\/h2>\n\n<ul>\n  <li>Ansl\u00e5ede og faktiske stemmer <strong>r\u00e6kker<\/strong> Stemmer det groft set overens? Hvis ikke: Tjek statistikker\/histogrammer.<\/li>\n  <li>Er der en node, der dominerer \u201etime to last row\u201c? F\u00f8rste kandidat til optimering (indeks, valg af sammenf\u00f8jning, undg\u00e5else af sortering).<\/li>\n  <li>Er \u201eloops\u201c meget h\u00f8je? Forbedr join-driveren\/indekset p\u00e5 den indre tabel, eller brug semi-join.<\/li>\n  <li>Er der sene sorteringer\/grupperinger? Tilpas indeksr\u00e6kkef\u00f8lgen og -retningen efter ORDER BY\/GROUP BY.<\/li>\n  <li>Er det virkelig n\u00f8dvendigt at hente alle kolonner i foresp\u00f8rgslen? Arbejd hen imod et covering-indeks, og stram SELECT-listen op.<\/li>\n  <li>En underforesp\u00f8rgsel pr. linje? Omskriv til JOIN eller materialiser.<\/li>\n  <li>Stabil over parametrene? M\u00e5l med flere realistiske v\u00e6rdier.<\/li>\n<\/ul>\n\n<h2>Almindelige fejlfortolkninger og hvordan jeg undg\u00e5r dem<\/h2>\n\n<p>Jeg stoler ikke blindt p\u00e5 ansl\u00e5ede tal <strong>Omkostninger<\/strong>, hvis det faktiske antal linjer afviger markant. Ligeledes drager jeg ingen forhastede konklusioner ud fra \u201etime to first row\u201c, hvis \u201etime to last row\u201c udg\u00f8r hovedparten <strong>b\u00e6rer<\/strong>. En hurtig start nytter ikke meget, hvis sortering eller sammenkobling dominerer i sidste ende. Desuden gennemg\u00e5r jeg sl\u00f8jfer grundigt, da de ofte skjuler en ineffektiv sammenkobling eller en underforesp\u00f8rgsel, der k\u00f8rer for hver linje. F\u00f8rst n\u00e5r k\u00f8rselsplanen, m\u00e5lev\u00e6rdierne og datafordelingen stemmer overens, \u00e6ndrer jeg <strong>Ting<\/strong>.<\/p>\n\n<h2>S\u00e6rlige tilf\u00e6lde: CTE\u2019er, afledte tabeller, partitioner<\/h2>\n\n<p>Common Table Expressions (CTE\u2019er) og afledte tabeller kan materialiseres eller sammenf\u00f8jes. I TREE opfatter jeg materialisering som et separat opbygningsskridt. Det er en fordel, hvis delstr\u00f8mmen bruges flere gange eller er dyr at beregne. Hvis CTE'er kun bruges \u00e9n gang og er selektive, er en sammenl\u00e6gning ofte mere effektiv, fordi der ikke kr\u00e6ves yderligere lagringsarbejde. Jeg holder \u00f8je med, om \u201etime to first row\u201c stiger markant \u2013 i s\u00e5 fald er materialiseringen muligvis overdimensioneret.<\/p>\n<p>Partitionerede tabeller er en hj\u00e6lp ved store datam\u00e6ngder, hvis pr\u00e6dikatet klart afgr\u00e6nser partitionerne. Jeg tjekker i udf\u00f8relsesplanen, om pruning finder anvendelse (kun f\u00e5 partitioner bliver scannet). Mangler dette, fordeles omkostningerne p\u00e5 alle partitioner \u2013 et tegn p\u00e5, at partitionsn\u00f8glerne b\u00f8r tilpasses de hyppigst anvendte filtre, eller at foresp\u00f8rgslen b\u00f8r formuleres s\u00e5ledes, at pruning bliver mulig.<\/p>\n\n<h2>Kort opsummeret<\/h2>\n\n<p>Med EXPLAIN ANALYZE g\u00f8r jeg MySQL-planer m\u00e5lbare og afd\u00e6kker hotspots, som jeg med <strong>Indekser<\/strong>, omformulering af foresp\u00f8rgsler og aktuelle statistikker. Jeg fokuserer p\u00e5 afvigelser mellem det ansl\u00e5ede og det faktiske antal r\u00e6kker, tiden indtil den f\u00f8rste og sidste r\u00e6kke samt <strong>Loops<\/strong>. Ud fra dette udleder jeg nogle f\u00e5, effektive trin og kontrollerer hver enkelt effekt igen med EXPLAIN ANALYZE. Med tiden genkender jeg m\u00f8nstre med det samme og iv\u00e6rks\u00e6tter passende tiltag hurtigere. P\u00e5 den m\u00e5de \u00f8ger jeg <strong>Ydelse<\/strong> p\u00e5lidelig og sikrer, at foresp\u00f8rgsler forbliver stabile p\u00e5 lang sigt.<\/p>","protected":false},"excerpt":{"rendered":"<p>L\u00e6r, hvordan du bruger MySQL EXPLAIN ANALYZE til at forst\u00e5 udf\u00f8relsesplaner og m\u00e5lrettet optimere dine SQL-foresp\u00f8rgsler ved hj\u00e6lp af s\u00f8geordet mysql explain analyze.<\/p>","protected":false},"author":1,"featured_media":21003,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[781],"tags":[],"class_list":["post-21010","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-datenbanken-administration-anleitungen"],"acf":[],"_wp_attached_file":null,"_wp_attachment_metadata":null,"litespeed-optimize-size":null,"litespeed-optimize-set":null,"_elementor_source_image_hash":null,"_wp_attachment_image_alt":null,"stockpack_author_name":null,"stockpack_author_url":null,"stockpack_provider":null,"stockpack_image_url":null,"stockpack_license":null,"stockpack_license_url":null,"stockpack_modification":null,"color":null,"original_id":null,"original_url":null,"original_link":null,"unsplash_location":null,"unsplash_sponsor":null,"unsplash_exif":null,"unsplash_attachment_metadata":null,"_elementor_is_screenshot":null,"surfer_file_name":null,"surfer_file_original_url":null,"envato_tk_source_kit":null,"envato_tk_source_index":null,"envato_tk_manifest":null,"envato_tk_folder_name":null,"envato_tk_builder":null,"envato_elements_download_event":null,"_menu_item_type":null,"_menu_item_menu_item_parent":null,"_menu_item_object_id":null,"_menu_item_object":null,"_menu_item_target":null,"_menu_item_classes":null,"_menu_item_xfn":null,"_menu_item_url":null,"_trp_menu_languages":null,"rank_math_primary_category":null,"rank_math_title":null,"inline_featured_image":null,"_yoast_wpseo_primary_category":null,"rank_math_schema_blogposting":null,"rank_math_schema_videoobject":null,"_oembed_049c719bc4a9f89deaead66a7da9fddc":null,"_oembed_time_049c719bc4a9f89deaead66a7da9fddc":null,"_yoast_wpseo_focuskw":null,"_yoast_wpseo_linkdex":null,"_oembed_27e3473bf8bec795fbeb3a9d38489348":null,"_oembed_c3b0f6959478faf92a1f343d8f96b19e":null,"_trp_translated_slug_en_us":null,"_wp_desired_post_slug":null,"_yoast_wpseo_title":null,"tldname":null,"tldpreis":null,"tldrubrik":null,"tldpolicylink":null,"tldsize":null,"tldregistrierungsdauer":null,"tldtransfer":null,"tldwhoisprivacy":null,"tldregistrarchange":null,"tldregistrantchange":null,"tldwhoisupdate":null,"tldnameserverupdate":null,"tlddeletesofort":null,"tlddeleteexpire":null,"tldumlaute":null,"tldrestore":null,"tldsubcategory":null,"tldbildname":null,"tldbildurl":null,"tldclean":null,"tldcategory":null,"tldpolicy":null,"tldbesonderheiten":null,"tld_bedeutung":null,"_oembed_d167040d816d8f94c072940c8009f5f8":null,"_oembed_b0a0fa59ef14f8870da2c63f2027d064":null,"_oembed_4792fa4dfb2a8f09ab950a73b7f313ba":null,"_oembed_33ceb1fe54a8ab775d9410abf699878d":null,"_oembed_fd7014d14d919b45ec004937c0db9335":null,"_oembed_21a029d076783ec3e8042698c351bd7e":null,"_oembed_be5ea8a0c7b18e658f08cc571a909452":null,"_oembed_a9ca7a298b19f9b48ec5914e010294d2":null,"_oembed_f8db6b27d08a2bb1f920e7647808899a":null,"_oembed_168ebde5096e77d8a89326519af9e022":null,"_oembed_cdb76f1b345b42743edfe25481b6f98f":null,"_oembed_87b0613611ae54e86e8864265404b0a1":null,"_oembed_27aa0e5cf3f1bb4bc416a4641a5ac273":null,"_oembed_time_27aa0e5cf3f1bb4bc416a4641a5ac273":null,"_tldname":null,"_tldclean":null,"_tldpreis":null,"_tldcategory":null,"_tldsubcategory":null,"_tldpolicy":null,"_tldpolicylink":null,"_tldsize":null,"_tldregistrierungsdauer":null,"_tldtransfer":null,"_tldwhoisprivacy":null,"_tldregistrarchange":null,"_tldregistrantchange":null,"_tldwhoisupdate":null,"_tldnameserverupdate":null,"_tlddeletesofort":null,"_tlddeleteexpire":null,"_tldumlaute":null,"_tldrestore":null,"_tldbildname":null,"_tldbildurl":null,"_tld_bedeutung":null,"_tldbesonderheiten":null,"_oembed_ad96e4112edb9f8ffa35731d4098bc6b":null,"_oembed_8357e2b8a2575c74ed5978f262a10126":null,"_oembed_3d5fea5103dd0d22ec5d6a33eff7f863":null,"_eael_widget_elements":null,"_oembed_0d8a206f09633e3d62b95a15a4dd0487":null,"_oembed_time_0d8a206f09633e3d62b95a15a4dd0487":null,"_aioseo_description":null,"_eb_attr":null,"_eb_data_table":null,"_oembed_819a879e7da16dd629cfd15a97334c8a":null,"_oembed_time_819a879e7da16dd629cfd15a97334c8a":null,"_acf_changed":null,"_wpcode_auto_insert":null,"_edit_last":null,"_edit_lock":null,"_oembed_e7b913c6c84084ed9702cb4feb012ddd":null,"_oembed_bfde9e10f59a17b85fc8917fa7edf782":null,"_oembed_time_bfde9e10f59a17b85fc8917fa7edf782":null,"_oembed_03514b67990db061d7c4672de26dc514":null,"_oembed_time_03514b67990db061d7c4672de26dc514":null,"rank_math_news_sitemap_robots":null,"rank_math_robots":null,"_eael_post_view_count":"118","_trp_automatically_translated_slug_ru_ru":null,"_trp_automatically_translated_slug_et":null,"_trp_automatically_translated_slug_lv":null,"_trp_automatically_translated_slug_fr_fr":null,"_trp_automatically_translated_slug_en_us":null,"_wp_old_slug":null,"_trp_automatically_translated_slug_da_dk":null,"_trp_automatically_translated_slug_pl_pl":null,"_trp_automatically_translated_slug_es_es":null,"_trp_automatically_translated_slug_hu_hu":null,"_trp_automatically_translated_slug_fi":null,"_trp_automatically_translated_slug_ja":null,"_trp_automatically_translated_slug_lt_lt":null,"_elementor_edit_mode":null,"_elementor_template_type":null,"_elementor_version":null,"_elementor_pro_version":null,"_wp_page_template":null,"_elementor_page_settings":null,"_elementor_data":null,"_elementor_css":null,"_elementor_conditions":null,"_happyaddons_elements_cache":null,"_oembed_75446120c39305f0da0ccd147f6de9cb":null,"_oembed_time_75446120c39305f0da0ccd147f6de9cb":null,"_oembed_3efb2c3e76a18143e7207993a2a6939a":null,"_oembed_time_3efb2c3e76a18143e7207993a2a6939a":null,"_oembed_59808117857ddf57e478a31d79f76e4d":null,"_oembed_time_59808117857ddf57e478a31d79f76e4d":null,"_oembed_965c5b49aa8d22ce37dfb3bde0268600":null,"_oembed_time_965c5b49aa8d22ce37dfb3bde0268600":null,"_oembed_81002f7ee3604f645db4ebcfd1912acf":null,"_oembed_time_81002f7ee3604f645db4ebcfd1912acf":null,"_elementor_screenshot":null,"_oembed_7ea3429961cf98fa85da9747683af827":null,"_oembed_time_7ea3429961cf98fa85da9747683af827":null,"_elementor_controls_usage":null,"_elementor_page_assets":[],"_elementor_screenshot_failed":null,"theplus_transient_widgets":null,"_eael_custom_js":null,"_wp_old_date":null,"_trp_automatically_translated_slug_it_it":null,"_trp_automatically_translated_slug_pt_pt":null,"_trp_automatically_translated_slug_zh_cn":null,"_trp_automatically_translated_slug_nl_nl":null,"_trp_automatically_translated_slug_pt_br":null,"_trp_automatically_translated_slug_sv_se":null,"rank_math_analytic_object_id":null,"rank_math_internal_links_processed":"1","_trp_automatically_translated_slug_ro_ro":null,"_trp_automatically_translated_slug_sk_sk":null,"_trp_automatically_translated_slug_bg_bg":null,"_trp_automatically_translated_slug_sl_si":null,"litespeed_vpi_list":null,"litespeed_vpi_list_mobile":null,"rank_math_seo_score":null,"rank_math_contentai_score":null,"ilj_limitincominglinks":null,"ilj_maxincominglinks":null,"ilj_limitoutgoinglinks":null,"ilj_maxoutgoinglinks":null,"ilj_limitlinksperparagraph":null,"ilj_linksperparagraph":null,"ilj_blacklistdefinition":null,"ilj_linkdefinition":null,"_eb_reusable_block_ids":null,"rank_math_focus_keyword":"mysql explain","rank_math_og_content_image":null,"_yoast_wpseo_metadesc":null,"_yoast_wpseo_content_score":null,"_yoast_wpseo_focuskeywords":null,"_yoast_wpseo_keywordsynonyms":null,"_yoast_wpseo_estimated-reading-time-minutes":null,"rank_math_description":null,"surfer_last_post_update":null,"surfer_last_post_update_direction":null,"surfer_keywords":null,"surfer_location":null,"surfer_draft_id":null,"surfer_permalink_hash":null,"surfer_scrape_ready":null,"_thumbnail_id":"21003","footnotes":null,"_links":{"self":[{"href":"https:\/\/webhosting.de\/da\/wp-json\/wp\/v2\/posts\/21010","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/webhosting.de\/da\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/webhosting.de\/da\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/webhosting.de\/da\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/webhosting.de\/da\/wp-json\/wp\/v2\/comments?post=21010"}],"version-history":[{"count":0,"href":"https:\/\/webhosting.de\/da\/wp-json\/wp\/v2\/posts\/21010\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/webhosting.de\/da\/wp-json\/wp\/v2\/media\/21003"}],"wp:attachment":[{"href":"https:\/\/webhosting.de\/da\/wp-json\/wp\/v2\/media?parent=21010"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/webhosting.de\/da\/wp-json\/wp\/v2\/categories?post=21010"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/webhosting.de\/da\/wp-json\/wp\/v2\/tags?post=21010"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}