Content marketingMarketing plaćenog i organskog pretraživanja

WordPress: Rješavanje problema i optimizacija SQL upita predložaka pomoću SAVEQUERIES

Jedan uobičajeni krivac za tromost WordPress stranica nije nužno vaš domaćin, vaša CDN, ili čak veličine vaših slika - to je vaša baza podataka. Točnije, volumen i neučinkovitost SQL upiti koje generiraju vaša tema i dodaci. Svako učitavanje stranice može pokrenuti desetke - ili u loše optimiziranim slučajevima, stotine - upita bazi podataka. Kada se pomnože na widgete, kratke kodove, bočne trake i elemente uređivača blokova, ovi upiti mogu stvoriti ozbiljna uska grla u performansama koja prolaze nezapaženo, ali i dalje negativno utječu na vaše Core Web Vitals (CWV) i cjelokupno korisničko iskustvo.

Mnogi programeri se usredotočuju na predmemoriranje i CDN isporuku kako bi prikrili probleme s performansama, ali to rješava samo dio problema. Ako je temeljno učitavanje upita neučinkovito, u biti prekrivate hrđu. Prvi korak prema pravoj optimizaciji brzine je razumijevanje što se događa "ispod haube".

SPREMANJE UPITA

WordPress nudi ugrađenu konstantu, SAVEQUERIES, koji bilježi svaki upit baze podataka izvršen tijekom zahtjeva, uključujući i koliko dugo svaki upit traje. Kada se pažljivo koristi, to je neprocjenjiv dijagnostički alat za identificiranje neučinkovitosti u predlošcima tema, alatima za izradu stranica i integracijama dodataka.

Na dobro optimiziranoj WordPress stranici, tipičan predložak stranice trebao bi generirati između 20 i 50 upita. Minimalna početna stranica ili lagani izgled s jednom objavom mogli bi se približiti 20, dok bi složenija arhiva ili stranica WooCommerce proizvoda prirodno mogla dosegnuti 50 zbog pretraživanja taksonomije i metapodataka.

Sve što prelazi taj broj - posebno brojevi u stotinama - signalizira neučinkovitost. Svaki upit uvodi opterećenje, a čak se i mikrosekundna kašnjenja brzo povećavaju pod opterećenjem. Visok broj upita obično ukazuje na redundantne petlje, nekašene opcije ili dodatke koji izvršavaju vlastite pozive bazi podataka neovisno o glavnom WordPress upitu. Održavanje niskog broja upita ne odnosi se na proizvoljna ograničenja - radi se o osiguravanju da svaki upit ima razlog za postojanje i da vaši predlošci rade predvidljivo na svim stranicama.

omogućavanje SAVEQUERIES Na produkcijskoj stranici bez ikakvog oblika kontrole izlaza može biti previše. Možda ćete vidjeti tisuće upita na dnu vašeg HTML-a, što otežava precizno određivanje koji su predlošci ili komponente odgovorni za usporavanja. Rješenje je automatizirati zapisivanje tako da svaka vrsta predloška - naslovnica, stranica, pojedinačna objava, arhiva - generira vlastitu datoteku zapisnika. To pruža jasan, segmentiran prikaz gdje se događaju vaši najskuplji upiti.

Kako evidentirati upite prema WordPress predlošku

Evo jednostavnog, ali moćnog pristupa za učinkovito bilježenje WordPress upita. Postavljanjem sljedećeg koda u datoteku functions.php vaše teme ili prilagođeni dodatak, možete automatski snimati i pohranjivati ​​zapisnike upita kad god ste prijavljeni kao administrator i SAVEQUERIES je omogućen.

// If SAVEQUERIES is enabled, print the queries in the footer in an HTML tag
function log_queries_to_file() {
    global $wpdb;

    // Check conditions: SAVEQUERIES enabled and logged-in admin
    if (defined('SAVEQUERIES') && SAVEQUERIES && is_user_logged_in() && current_user_can('manage_options')) {
        // Define the log directory (site root/queries/)
        $log_dir = ABSPATH . 'queries/';
        
        // Create the directory if it doesn't exist (with recursive creation and proper permissions)
        if (!file_exists($log_dir)) {
            mkdir($log_dir, 0755, true);
        }
        
        // Skip if directory isn't writable
        if (!is_writable($log_dir)) {
            return; // Or add error logging if desired
        }
        
        // Determine the filename based on page type
        $filename = '';
        
        if (is_front_page()) {
            $filename = 'queries-frontpage.log';
        } elseif (is_page()) {
            $template_slug = get_page_template_slug(get_the_ID());
            if (empty($template_slug)) {
                $template_slug = 'default';
            } else {
                // Sanitize template slug: basename without .php
                $template_slug = basename($template_slug, '.php');
            }
            $filename = 'queries-page-' . sanitize_title($template_slug) . '.log';
        } elseif (is_archive()) {
            $post_type = 'post'; // Default for standard archives
            if (is_post_type_archive()) {
                $post_type = get_query_var('post_type');
                if (is_array($post_type)) {
                    $post_type = reset($post_type); // Handle multi-type, take first
                }
            } elseif (is_category() || is_tag() || is_tax()) {
                // For taxonomies, get the post type from queried object if custom
                $queried = get_queried_object();
                if ($queried && isset($queried->taxonomy)) {
                    $tax = get_taxonomy($queried->taxonomy);
                    $post_type = is_array($tax->object_type) ? reset($tax->object_type) : $tax->object_type;
                }
            } elseif (is_author() || is_date()) {
                $post_type = 'post';
            }
            $filename = 'queries-archive-' . sanitize_title($post_type) . '.log';
        } elseif (is_singular()) { // Covers single posts, pages, CPTs
            $post_type = get_post_type(get_the_ID());
            $filename = 'queries-single-' . sanitize_title($post_type) . '.log';
        }
        
        // If no matching type, skip or use a fallback like 'queries-other.log'
        if (empty($filename)) {
            return;
        }
        
        // Full file path
        $file_path = $log_dir . $filename;
        
        // Prepare log content (queries list with optional header)
        $log_content = "\n\n=== Queries for " . esc_url_raw(home_url(add_query_arg(array(), $GLOBALS['wp']->request))) . " on " . current_time('mysql') . " ===\n";
        $log_content .= print_r($wpdb->queries, true);
        
        // Append to file (creates if not exists)
        file_put_contents($file_path, $log_content, FILE_APPEND | LOCK_EX);
    }
}
add_action('shutdown', 'log_queries_to_file');

Nakon što je omogućeno, pronaći ćete /queries/ direktorij u korijenskom direktoriju vašeg WordPressa koji sadrži datoteke zapisnika kao što su queries-frontpage.log ili queries-single-post.log. Prijavljen kao administrator, posjetio sam svaki URL koji je uključivao jedan od mojih predložaka kako bih zabilježio upite i njihovu učinkovitost.

Kako čitati podatke SAVEQUERIES

Svaki unos prikazat će tekst upita, vrijeme izvršavanja i stog poziva funkcije koji ga je pokrenuo. Tijekom vremena, to vam daje profil koji predlošci i značajke generiraju najveće opterećenje.

[20] => Array
        (
            [0] => SELECT wp_posts.ID FROM wp_posts  LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
WHERE 1=1  AND ( wp_term_relationships.term_taxonomy_id IN (32489)
) AND wp_posts.post_type = 'nav_menu_item' AND ((wp_posts.post_status = 'publish')) GROUP BY wp_posts.ID ORDER BY wp_posts.menu_order ASC		 
            [1] => 0.00042486190795898
            [2] => require('wp-blog-header.php'), require_once('wp-includes/template-loader.php'), include('/themes/jannah/page.php'), get_header, locate_template, load_template, require_once('/themes/mtz-23/header.php'), TIELABS_HELPER::get_template_part, include('/themes/jannah/templates/header/load.php'), TIELABS_HELPER::get_template_part, include('/themes/jannah/templates/header/nav-top.php'), wp_nav_menu, wp_get_nav_menu_items, get_posts, WP_Query->query, WP_Query->get_posts
            [3] => 1762916659.7638
            [4] => Array
                (
           )
)

Ovaj unos iz izlaza SAVEVUERIES predstavlja jedan SQL upit koji je izvršio WordPress, zajedno s detaljima o vremenu i kontekstu koji omogućuju praćenje gdje i zašto se izvršio. Svaki numerirani element polja odgovara upitu, a struktura pruža pet ključnih informacija:

  1. Sam upit — Vrijednost na indeksu [0] je sirova SQL naredba koju je WordPress poslao u bazu podataka. U ovom slučaju:
SELECT wp_posts.ID 
FROM wp_posts  
LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
WHERE 1=1  
  AND (wp_term_relationships.term_taxonomy_id IN (32489))
  AND wp_posts.post_type = 'nav_menu_item' 
  AND ((wp_posts.post_status = 'publish')) 
GROUP BY wp_posts.ID 
ORDER BY wp_posts.menu_order ASC
  1. Ovaj upit dohvaća sve objavljene stavke navigacijskog izbornika (post_type = 'nav_menu_item') koje pripadaju određenom pojmu izbornika (term_taxonomy_id = 32489). LEFT JOIN povezuje svaku stavku izbornika s njezinim taksonomskim odnosima, a klauzule GROUP BY i ORDER BY osiguravaju da se stavke izbornika vraćaju u definiranom redoslijedu. Ovo je tipičan upit koji se generira kada WordPress tema prikazuje navigacijski izbornik putem wp_nav_menu().
  2. Vrijeme izvršavanja upita — Vrijednost na indeksu [1] (0.00042486190795898) predstavlja vrijeme, u sekundama, koje je upitu bilo potrebno za izvršenje. U ovom slučaju, završen je za manje od pola milisekunde, što je izvrsno. Prilikom pregleda zapisnika, upiti koji stalno prelaze 0.02–0.05 sekundi potencijalni su kandidati za optimizaciju.
  3. Stog poziva — Vrijednost na indeksu [2] navodi cijeli PHP lanac poziva koji je doveo do ovog upita. Čitanje slijeva nadesno pokazuje da je upit potekao iz predloška zaglavlja teme tijekom renderiranja navigacijskog izbornika. Točnije, funkcija wp_nav_menu nazvana je wp_get_nav_menu_items, koja je pokrenula poziv get_posts, koji je na kraju izvršila metoda WP_Query->get_posts. Ovaj trag poziva ključan je za precizno određivanje koji je predložak ili funkcija pokrenula upit.
  4. Timestamp — Vrijednost na indeksu [3] (1762916659.7638) je Unix vremenska oznaka koja označava kada je upit izvršen tijekom zahtjeva. To pomaže u kronološkom poredanju upita ili njihovom povezivanju sa specifičnim sekvencama učitavanja.
  5. argumenti — Konačni niz na [4] je prazan u ovom primjeru, ali bi sadržavao sve vezane parametre ako bi upit koristio rezervirana mjesta.

Ukratko, ovaj unos u dnevnik pokazuje da je tema generirala standardni upit za dohvaćanje stavki navigacijskog izbornika za prikaz u zaglavlju web-mjesta. Iako je sam upit učinkovit, dobar je podsjetnik da svaka lokacija izbornika ili dinamički odjeljak može pokrenuti dodatne upite. Na složenim stranicama s više izbornika ili zaglavljima s widgetima, ove male, ponovljene pretrage mogu se zbrajati - što naglašava važnost keširanja izbornika i drugih statičnih elemenata web-mjesta kao moćne strategije optimizacije.

Kako optimizirati svoje predloške i upite

Nakon što ste utvrdili koji predlošci i komponente generiraju najviše upita, sljedeći korak je njihovo poboljšanje. Optimizacija upita u WordPressu nije samo stvar brzine - radi se o stabilnosti i skalabilnosti. Nekoliko ciljanih ispravaka može dramatično smanjiti opterećenje upitima, održavajući vaše stranice responzivnima čak i tijekom naglog porasta prometa.

  1. Uklonite nepotrebne upiteMnoge WordPress teme i dodaci upituju podatke koje zapravo ne koriste. Na primjer, neki će dohvatiti sve metapodatke objave kada im je potrebno samo jedno polje ili će pozvati get_posts() unutar petlji umjesto da se oslanjaju na glavni upit. Pregledajte datoteke predložaka i uklonite suvišne pozive baze podataka, posebno unutar petlji ili u ponovljenim komponentama kao što su zaglavlja i podnožja. Kad god je moguće, zamijenite dinamički sadržaj vođen bazom podataka statičkim oznakama predložaka ili unaprijed izračunatim vrijednostima.
  2. Smanjite količinu upita predmemoriranjemJedan od najučinkovitijih načina za poboljšanje učinkovitosti jest keširanje često dostupnih informacija koje se rijetko mijenjaju. Na primjer, izbornici, područja widgeta ili opcije web-mjesta mogu se keširati u privremenim datotekama ili u predmemoriji objekata kako bi se spriječilo ponovljeno pretraživanje pri svakom učitavanju stranice. Izbornik web-mjesta, na primjer, može se dohvatiti i pohraniti u privremenim datotekama koje se ažuriraju samo kada se sam izbornik promijeni. Ovaj pristup rasterećuje ponavljajuće upite i dramatično smanjuje opterećenje baze podataka bez žrtvovanja svježine.
  3. Optimizirajte bazu podataka pravilnim indeksiranjemVremenom, WordPress baze podataka postaju velike i fragmentirane, posebno na web-lokacijama s opsežnim postmeta ili commentmeta tablicama. Dodavanje odgovarajućih indeksa često upitanim stupcima - kao što su meta_key i meta_value - može napraviti veliku razliku. Mnogi dodaci, uključujući Query Monitor i WP-Optimize, mogu istaknuti spore upite i predložiti poboljšanja indeksiranja. Povremena optimizacija tablica i čišćenje napuštenih podataka također pomaže MySQL-u da učinkovitije obrađuje upite.
  4. Iskoristite alate za predmemoriranje baze podatakaNakon što vaši upiti postanu što učinkovitiji, keširanje njihovih rezultata može značajno poboljšati performanse. Sustavi za keširanje objekata poput Redisa ili Memcacheda pohranjuju rezultate upita i PHP objekte u memoriju, tako da WordPress može dohvatiti rezultate upita i PHP objekte u memoriju, tako da ih WordPress može dohvatiti bez ponovljenog kontakta s bazom podataka. To je posebno učinkovito za web-lokacije s velikim prometom ili one sa složenim obrascima upita, gdje se iste pretrage postmeta ili taksonomije događaju na više zahtjeva. Trajno keširanje objekata osigurava da, nakon što se podaci dohvate, ostanu brzo dostupni dok se izričito ne ponište - značajno smanjujući opterećenje MySQL-a i poboljšavajući vrijeme odziva. Mnogi moderni hostovi nude integraciju s Redisom ili Memcachedom, a WordPress ih izvorno podržava putem dodataka za keširanje kao što je object-cache.php.
  5. Koristite alate za predmemoriranje stranica i CDNOsim poboljšanja na razini baze podataka, rješenja za predmemoriranje cijele stranice sprječavaju da mnoge stranice uopće pozivaju WordPress ili MySQL. Dodaci poput WP Rocket, W3 Total Cache i LiteSpeed ​​Cache mogu generirati i pohranjivati ​​statičke verzije vaših stranica, odmah ih poslužujući posjetiteljima. Na sloju poslužitelja, Nginx FastCGI cache ili Varnish postiže isti učinak uz još niže opterećenje. Dodavanje mreže za isporuku sadržaja (CDN) poput Cloudflarea ili BunnyCDN-a proširuje ovo keširanjem i distribucijom tih statičkih resursa globalno, minimizirajući latenciju za korisnike bez obzira na njihovu lokaciju. CDN-ovi također mogu keširati potpune HTML snimke za anonimne posjetitelje, što znači da vaš izvorni poslužitelj rijetko obrađuje dinamičke zahtjeve. Zajedno, ovi slojevi predmemoriranja tvore kaskadni hijerarhijski sloj - predmemoriju baze podataka, predmemoriju objekata, predmemoriju stranica i CDN predmemoriju - koji osigurava da WordPress isporučuje stranice što je brže moguće, a istovremeno dramatično smanjuje upite i rad poslužitelja.

Zaključak

Performanse baze podataka jedan su od najzanemarenijih aspekata WordPress optimizacije. Dok dodaci, skripte i slike često preuzimaju krivnju za sporo vrijeme učitavanja, prekomjerni i neučinkoviti upiti često su pravi krivci. Omogućavanjem SAVECUERIES-a, zapisivanjem podataka upita prema predlošku i sustavnim rješavanjem problematičnih područja možete otkriti neučinkovitosti koje većina programera nikada ne vidi.

Uklanjanje nepotrebnih upita, inteligentno keširanje, optimizacija tablica i implementacija višeslojnih rješenja za keširanje mogu transformirati WordPress iz platformi prepune upita. CMS u brzu, skalabilnu platformu za objavljivanje. Prava brzina se ne postiže skrivanjem neučinkovitosti samo putem predmemoriranja - počinje s razumijevanjem i ispravljanjem temeljnog uzroka neučinkovitosti: načina na koji vaša web-lokacija komunicira sa svojom bazom podataka.

Natrag na vrh
Zatvori

Otkriven je Adblock

Oslanjamo se na oglase i sponzorstva kako bismo ostali Martech Zone besplatno. Razmislite o onemogućavanju blokatora oglasa ili nas podržite pristupačnom godišnjom članarinom bez oglasa (10 USD):

Prijavite se za godišnje članstvo