Skip to content

Il database MySQL (o MariaDB) è il cuore di ogni installazione WordPress. Ogni post, ogni opzione, ogni metadato transita per le 12 tabelle del core. La capacità di interrogare, diagnosticare e ottimizzare direttamente il database con SQL è una competenza che separa chi gestisce WordPress da chi lo subisce.

Questa guida raccoglie le query SQL che uso regolarmente nella manutenzione di database WordPress in produzione: dalla diagnostica delle tabelle alla pulizia di dati orfani, dall’ottimizzazione degli indici alla configurazione del server. Ogni query è testata su MySQL 8.4 e MariaDB 10.11+ — le versioni raccomandate per WordPress 6.x.

Nota: prima di eseguire qualsiasi query di tipo DELETE o UPDATE, esegui sempre un backup completo del database. Le query diagnostiche (SELECT) sono sicure e non modificano dati.

Schema del database WordPress: tabelle e relazioni

WordPress 6.x usa 12 tabelle core con prefisso configurabile (default wp_). Lo schema è rimasto stabile dal 2015 (WordPress 4.4, che aggiunse wp_termmeta). Le modifiche nelle versioni 6.x riguardano principalmente la colonna autoload di wp_options e aggiustamenti agli indici.

Un aspetto critico: WordPress non usa foreign key constraints a livello database. Tutte le relazioni tra tabelle sono gestite dal codice PHP applicativo. Questa scelta progettuale (ereditata dall’epoca MyISAM) è la causa principale dei dati orfani che si accumulano nel tempo.

wp_posts              -- Post, pagine, allegati, revisioni, menu, CPT
  |
  |-- wp_postmeta         -- Metadati key/value (post_id → wp_posts.ID)
  |-- wp_comments          -- Commenti (comment_post_ID → wp_posts.ID)
  |     |
  |     +-- wp_commentmeta -- Metadati commenti (comment_id → wp_comments.comment_ID)
  |
  +-- wp_term_relationships -- Relazione N:N post↔termini (object_id → wp_posts.ID)
        |
        +-- wp_term_taxonomy  -- Contesto tassonomico (category, post_tag, custom)
              |
              +-- wp_terms        -- Nomi e slug dei termini
                    |
                    +-- wp_termmeta   -- Metadati termini (da WP 4.4)

wp_users              -- Account utenti
  |
  +-- wp_usermeta         -- Metadati utenti (user_id → wp_users.ID)

wp_options            -- Opzioni globali del sito, transient, configurazioni plugin
wp_links              -- Blogroll (deprecata, tabella ancora presente)

Le tabelle più problematiche in termini di crescita incontrollata sono wp_postmeta e wp_options. La prima accumula metadati da plugin disattivati e revisioni; la seconda si appesantisce con transient scaduti e opzioni autoloaded di plugin rimossi.

Diagnostica: dimensioni e stato delle tabelle

La prima operazione di qualsiasi intervento di manutenzione è capire lo stato attuale del database. Questa query restituisce dimensione dati, indici, spazio libero e percentuale di frammentazione per ogni tabella WordPress:

SELECT
    TABLE_NAME,
    TABLE_ROWS,
    ROUND(DATA_LENGTH / 1024 / 1024, 2) AS data_mb,
    ROUND(INDEX_LENGTH / 1024 / 1024, 2) AS index_mb,
    ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS total_mb,
    ROUND(DATA_FREE / 1024 / 1024, 2) AS free_space_mb,
    ROUND(DATA_FREE / (DATA_LENGTH + INDEX_LENGTH + DATA_FREE) * 100, 2) AS fragmentation_pct
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE()
    AND TABLE_NAME LIKE 'wp_%'
ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC;

Una frammentazione superiore al 20% dopo una pulizia massiva giustifica un OPTIMIZE TABLE. Per la diagnostica di routine, basta ANALYZE TABLE che aggiorna le statistiche degli indici senza ricostruire la tabella.

Pulizia dei dati orfani in wp_postmeta

wp_postmeta è tipicamente la tabella più grande di un’installazione WordPress. Senza foreign key, i metadati restano nel database anche dopo l’eliminazione dei post associati. Plugin come ACF, Yoast, WooCommerce creano decine di meta_key per ogni post — e quando un post viene cancellato, i relativi metadati spesso restano orfani.

Diagnostica: contare i metadati orfani

-- Conta postmeta senza post associato
SELECT COUNT(*) AS orphaned_postmeta_count
FROM wp_postmeta pm
LEFT JOIN wp_posts p ON pm.post_id = p.ID
WHERE p.ID IS NULL;

-- Anteprima dei record orfani (primi 50)
SELECT pm.meta_id, pm.post_id, pm.meta_key,
       LEFT(pm.meta_value, 100) AS meta_value_preview
FROM wp_postmeta pm
LEFT JOIN wp_posts p ON pm.post_id = p.ID
WHERE p.ID IS NULL
LIMIT 50;

Pulizia: eliminare i metadati orfani

DELETE pm
FROM wp_postmeta pm
LEFT JOIN wp_posts p ON pm.post_id = p.ID
WHERE p.ID IS NULL;

Eliminare uno specifico meta_key

Quando l’URL di un post pubblicato viene aggiornato, WordPress salva il precedente URL in _wp_old_slug e crea un redirect 301 automatico. Se gestisci le redirezioni in modo diverso (plugin dedicato o .htaccess), queste entry si accumulano inutilmente:

-- Visualizza tutti i vecchi slug salvati
SELECT * FROM wp_postmeta WHERE meta_key = '_wp_old_slug';

-- Elimina un singolo slug specifico
DELETE FROM wp_postmeta
WHERE meta_key = '_wp_old_slug' AND meta_value = 'il-vecchio-slug';

-- Elimina tutti i vecchi slug
DELETE FROM wp_postmeta WHERE meta_key = '_wp_old_slug';

Trovare e rimuovere metadati duplicati

I duplicati in wp_postmeta sono più frequenti di quanto si pensi. Plugin con bug, import multipli, e hook mal configurati generano entry duplicate che appesantiscono le query. Con MySQL 8.0+ e MariaDB 10.5+ possiamo usare le window function per identificarli con precisione:

Diagnostica: trovare i duplicati

-- Duplicati per combinazione post_id + meta_key
SELECT post_id, meta_key, COUNT(*) AS duplicate_count
FROM wp_postmeta
GROUP BY post_id, meta_key
HAVING COUNT(*) > 1
ORDER BY duplicate_count DESC
LIMIT 50;

-- Duplicati esatti (stesso post_id + meta_key + meta_value)
SELECT post_id, meta_key, meta_value, COUNT(*) AS exact_dup_count
FROM wp_postmeta
GROUP BY post_id, meta_key, meta_value
HAVING COUNT(*) > 1
ORDER BY exact_dup_count DESC
LIMIT 50;

Pulizia: eliminare i duplicati con ROW_NUMBER()

-- Mantiene il meta_id più basso, elimina i duplicati (MySQL 8+)
DELETE FROM wp_postmeta
WHERE meta_id IN (
    SELECT meta_id FROM (
        SELECT meta_id,
               ROW_NUMBER() OVER (
                   PARTITION BY post_id, meta_key, meta_value
                   ORDER BY meta_id ASC
               ) AS rn
        FROM wp_postmeta
    ) ranked
    WHERE rn > 1
);

Pulizia dei transient in wp_options

I transient di WordPress sono dati temporanei con scadenza, salvati in wp_options quando non è configurato un object cache persistente (Redis/Memcached). Plugin, temi e il core stesso li usano per cache temporanee. Il problema: i transient scaduti non vengono eliminati automaticamente — restano nel database finché qualcuno non li richiama o li pulisce manualmente.

Diagnostica: stato dei transient

SELECT
    COUNT(*) AS total_transients,
    SUM(CASE WHEN option_name LIKE '_transient_timeout_%' THEN 1 ELSE 0 END) AS timeout_entries,
    SUM(CASE WHEN option_name LIKE '_transient_%'
             AND option_name NOT LIKE '_transient_timeout_%' THEN 1 ELSE 0 END) AS value_entries,
    SUM(CASE WHEN option_name LIKE '_site_transient_%' THEN 1 ELSE 0 END) AS site_transients
FROM wp_options
WHERE option_name LIKE '%transient%';

Pulizia: eliminare i transient scaduti

-- Elimina solo i transient effettivamente scaduti (data + timeout)
DELETE a, b FROM wp_options a
JOIN wp_options b
    ON b.option_name = CONCAT('_transient_timeout_', SUBSTRING(a.option_name, 12))
WHERE a.option_name LIKE '_transient_%'
    AND a.option_name NOT LIKE '_transient_timeout_%'
    AND b.option_value < UNIX_TIMESTAMP();

Opzioni autoloaded: il killer silenzioso delle performance

Ad ogni richiesta, WordPress carica in memoria tutte le opzioni con autoload attivo dalla tabella wp_options. Con WordPress 6.6+ la colonna autoload accetta i valori on, off, auto, auto-on oltre ai legacy yes/no. Il valore auto permette a WordPress di decidere autonomamente in base alla dimensione dell’opzione.

Il benchmark ideale è sotto gli 800 KB di dati autoloaded totali. Sopra i 3 MB ci sono problemi evidenti di performance — spesso causati da plugin disattivati che lasciano le proprie opzioni in autoload.

Diagnostica: dimensione totale autoloaded

-- Compatibile con WP 6.6+ (include tutti i valori autoload attivi)
SELECT
    ROUND(SUM(LENGTH(option_value)) / 1024, 2) AS autoload_size_kb,
    COUNT(*) AS autoload_count
FROM wp_options
WHERE autoload IN ('yes', 'on', 'auto', 'auto-on');

Le 20 opzioni autoloaded più grandi

SELECT option_name,
       LENGTH(option_value) AS size_bytes,
       ROUND(LENGTH(option_value) / 1024, 2) AS size_kb,
       ROUND(LENGTH(option_value) / 1024 / 1024, 4) AS size_mb
FROM wp_options
WHERE autoload IN ('yes', 'on', 'auto', 'auto-on')
ORDER BY size_bytes DESC
LIMIT 20;

Disabilitare l’autoload di un’opzione specifica

UPDATE wp_options SET autoload = 'no' WHERE option_name = 'nome_opzione_qui';

Revisioni dei post: impatto sul database e pulizia

WordPress salva una revisione per ogni salvataggio di un post. Un articolo modificato 50 volte genera 50 copie complete del contenuto in wp_posts, ognuna con i relativi metadati in wp_postmeta. Su siti con centinaia di post e redattori attivi, le revisioni possono rappresentare il 60-70% delle righe totali di wp_posts.

Diagnostica: impatto delle revisioni

-- Conteggio e dimensione totale delle revisioni
SELECT
    COUNT(*) AS total_revisions,
    ROUND(SUM(LENGTH(post_content)) / 1024 / 1024, 2) AS content_size_mb
FROM wp_posts
WHERE post_type = 'revision';

-- Post con più revisioni (top 20)
SELECT
    p.post_parent,
    parent.post_title AS original_title,
    COUNT(p.ID) AS revision_count,
    ROUND(SUM(LENGTH(p.post_content)) / 1024, 2) AS revisions_size_kb
FROM wp_posts p
JOIN wp_posts parent ON p.post_parent = parent.ID
WHERE p.post_type = 'revision'
GROUP BY p.post_parent, parent.post_title
ORDER BY revision_count DESC
LIMIT 20;

-- Overhead dei metadati delle revisioni
SELECT COUNT(*) AS revision_meta_rows,
       ROUND(SUM(LENGTH(meta_value)) / 1024 / 1024, 2) AS meta_size_mb
FROM wp_postmeta
WHERE post_id IN (SELECT ID FROM wp_posts WHERE post_type = 'revision');

Pulizia: eliminare tutte le revisioni

-- Elimina revisioni + metadati + relazioni tassonomiche in un'unica operazione
DELETE a, b, c
FROM wp_posts a
LEFT JOIN wp_term_relationships b ON a.ID = b.object_id
LEFT JOIN wp_postmeta c ON a.ID = c.post_id
WHERE a.post_type = 'revision';

Per limitare le revisioni future, aggiungi a wp-config.php:

define('WP_POST_REVISIONS', 5);     // massimo 5 revisioni per post
define('AUTOSAVE_INTERVAL', 300);   // autosave ogni 5 minuti (default: 60 secondi)

Pulizia dei commenti spam e metadati

-- Statistiche commenti per stato
SELECT
    comment_approved,
    COUNT(*) AS count,
    CASE comment_approved
        WHEN '1' THEN 'Approvati'
        WHEN '0' THEN 'In attesa'
        WHEN 'spam' THEN 'Spam'
        WHEN 'trash' THEN 'Cestino'
    END AS stato
FROM wp_comments
GROUP BY comment_approved;

-- Elimina commenti spam + relativi metadati in un passaggio
DELETE cm, c
FROM wp_comments c
LEFT JOIN wp_commentmeta cm ON c.comment_ID = cm.comment_id
WHERE c.comment_approved = 'spam';

-- Elimina commentmeta orfani (commento non più esistente)
DELETE cm
FROM wp_commentmeta cm
LEFT JOIN wp_comments c ON cm.comment_id = c.comment_ID
WHERE c.comment_ID IS NULL;

-- Aggiorna il conteggio commenti cachati su wp_posts
UPDATE wp_posts p
SET comment_count = (
    SELECT COUNT(*)
    FROM wp_comments c
    WHERE c.comment_post_ID = p.ID
      AND c.comment_approved = '1'
);

Relazioni tassonomiche orfane e conteggi disallineati

Le relazioni tra post e tassonomie (categorie, tag, tassonomie custom) passano per tre tabelle: wp_terms, wp_term_taxonomy e wp_term_relationships. Quando un post viene eliminato, le relazioni in wp_term_relationships possono restare orfane. Il campo count in wp_term_taxonomy è un conteggio cachato che può disallinearsi.

-- Relazioni orfane: il post non esiste più
SELECT COUNT(*) AS orphaned_by_object
FROM wp_term_relationships tr
LEFT JOIN wp_posts p ON tr.object_id = p.ID
WHERE p.ID IS NULL;

-- Pulizia
DELETE tr
FROM wp_term_relationships tr
LEFT JOIN wp_posts p ON tr.object_id = p.ID
WHERE p.ID IS NULL;

-- Termini con conteggio disallineato rispetto alle relazioni effettive
SELECT tt.term_taxonomy_id, t.name, tt.taxonomy,
       tt.count AS conteggio_cachato,
       COALESCE(actual.real_count, 0) AS conteggio_reale
FROM wp_term_taxonomy tt
JOIN wp_terms t ON tt.term_id = t.term_id
LEFT JOIN (
    SELECT term_taxonomy_id, COUNT(*) AS real_count
    FROM wp_term_relationships
    GROUP BY term_taxonomy_id
) actual ON tt.term_taxonomy_id = actual.term_taxonomy_id
WHERE tt.count != COALESCE(actual.real_count, 0);

-- Riallinea i conteggi
UPDATE wp_term_taxonomy tt
SET tt.count = (
    SELECT COUNT(*)
    FROM wp_term_relationships tr
    WHERE tr.term_taxonomy_id = tt.term_taxonomy_id
);

Query avanzate con CTE e window function (MySQL 8+)

MySQL 8.0 e MariaDB 10.5+ supportano le Common Table Expressions (CTE) e le window function. Queste funzionalità trasformano la capacità di analisi sui dati WordPress, rendendo possibili query che prima richiedevano stored procedure o script esterni.

CTE ricorsiva: albero completo delle pagine

WordPress gestisce la gerarchia delle pagine con il campo post_parent in wp_posts. Una CTE ricorsiva permette di ricostruire l’intero albero con la profondità di annidamento:

WITH RECURSIVE page_tree AS (
    SELECT ID, post_title, post_parent, post_name, 0 AS depth
    FROM wp_posts
    WHERE post_type = 'page' AND post_status = 'publish' AND post_parent = 0

    UNION ALL

    SELECT p.ID, p.post_title, p.post_parent, p.post_name, pt.depth + 1
    FROM wp_posts p
    JOIN page_tree pt ON p.post_parent = pt.ID
    WHERE p.post_type = 'page' AND p.post_status = 'publish'
)
SELECT ID, CONCAT(REPEAT('  ', depth), post_title) AS titolo_indentato,
       post_name, depth
FROM page_tree
ORDER BY depth, post_title;

CTE ricorsiva: gerarchia delle categorie

WITH RECURSIVE category_tree AS (
    SELECT t.term_id, t.name, tt.parent, 0 AS depth
    FROM wp_terms t
    JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
    WHERE tt.taxonomy = 'category' AND tt.parent = 0

    UNION ALL

    SELECT t.term_id, t.name, tt.parent, ct.depth + 1
    FROM wp_terms t
    JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
    JOIN category_tree ct ON tt.parent = ct.term_id
    WHERE tt.taxonomy = 'category'
)
SELECT * FROM category_tree ORDER BY depth, name;

Funzioni JSON: esportare tag come array JSON

Le funzioni JSON di MySQL 8+ sono utili per esportazioni dati e integrazioni con sistemi esterni:

SELECT p.ID, p.post_title,
       JSON_ARRAYAGG(t.name) AS tags_json
FROM wp_posts p
JOIN wp_term_relationships tr ON p.ID = tr.object_id
JOIN wp_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
JOIN wp_terms t ON tt.term_id = t.term_id
WHERE tt.taxonomy = 'post_tag' AND p.post_status = 'publish'
GROUP BY p.ID, p.post_title;

Indici personalizzati per wp_postmeta

Gli indici di default di WordPress su wp_postmeta sono insufficienti per siti con più di qualche migliaio di post. L’indice su meta_key è singolo e copre solo i primi 191 caratteri. Le meta_query di WP_Query che filtrano per meta_key + meta_value producono scan completi della tabella.

-- Verifica indici attuali
SHOW INDEX FROM wp_postmeta;

-- Indice composito per il pattern più comune: get meta by post_id + meta_key
ALTER TABLE wp_postmeta ADD INDEX idx_postid_metakey (post_id, meta_key(191));

-- Indice composito per meta_query: trova post per meta_key + meta_value
ALTER TABLE wp_postmeta ADD INDEX idx_metakey_metavalue (meta_key(191), meta_value(20));

-- Stesso pattern per wp_usermeta
ALTER TABLE wp_usermeta ADD INDEX idx_userid_metakey (user_id, meta_key(191));

-- Indice per accelerare le query autoload su wp_options
ALTER TABLE wp_options ADD INDEX idx_autoload (autoload);

-- Dopo l'aggiunta degli indici, aggiorna le statistiche
ANALYZE TABLE wp_postmeta;
ANALYZE TABLE wp_usermeta;
ANALYZE TABLE wp_options;

Analisi delle query lente con EXPLAIN

Il comando EXPLAIN è lo strumento fondamentale per capire come MySQL esegue una query. MySQL 8.0.18+ supporta anche EXPLAIN ANALYZE, che esegue effettivamente la query e mostra i tempi reali.

-- EXPLAIN base
EXPLAIN SELECT p.ID, p.post_title
FROM wp_posts p
JOIN wp_postmeta pm ON p.ID = pm.post_id
WHERE pm.meta_key = '_thumbnail_id'
  AND p.post_status = 'publish'
  AND p.post_type = 'post';

-- EXPLAIN ANALYZE con tempi reali (MySQL 8.0.18+)
EXPLAIN ANALYZE SELECT p.ID, p.post_title
FROM wp_posts p
JOIN wp_postmeta pm ON p.ID = pm.post_id
WHERE pm.meta_key = '_thumbnail_id'
  AND p.post_status = 'publish';

Nell’output di EXPLAIN, la colonna type indica l’efficienza dell’accesso alla tabella:

typeSignificatoPerformance
constMatch singola riga via PRIMARY KEYOttima
eq_refUna riga per ogni riga dalla tabella precedente (PK/UNIQUE join)Eccellente
refRighe multiple via indice non-uniqueBuona
rangeScansione range su indice (BETWEEN, IN, >, <)Accettabile
indexScansione completa dell’indiceScarsa
ALLFull table scan, nessun indice usatoPessima

Se nella colonna Extra compare Using filesort o Using temporary, la query sta eseguendo operazioni aggiuntive costose che possono essere eliminate con indici appropriati.

Manutenzione delle tabelle: ANALYZE e OPTIMIZE

-- ANALYZE TABLE: aggiorna le statistiche degli indici
-- Sicuro, non bloccante su InnoDB, da eseguire settimanalmente
ANALYZE TABLE wp_posts;
ANALYZE TABLE wp_postmeta;
ANALYZE TABLE wp_options;
ANALYZE TABLE wp_comments;
ANALYZE TABLE wp_term_relationships;

-- OPTIMIZE TABLE: ricostruisce la tabella e deframmenta
-- Per InnoDB equivale a ALTER TABLE ... FORCE (rebuild completo)
-- Usa solo dopo pulizie massive (eliminazione 50%+ righe)
OPTIMIZE TABLE wp_postmeta;
OPTIMIZE TABLE wp_options;

-- CHECK TABLE: verifica integrità strutturale
CHECK TABLE wp_posts, wp_postmeta, wp_options;

Nota: OPTIMIZE TABLE su InnoDB richiede spazio disco pari alla dimensione della tabella e blocca brevemente le scritture. Non è necessario nella manutenzione di routine — InnoDB riutilizza lo spazio liberato automaticamente. Usalo solo dopo operazioni massive come la pulizia di migliaia di revisioni.

InnoDB vs MyISAM: la scelta definitiva

Se sul tuo server trovi ancora tabelle MyISAM, convertile immediatamente. InnoDB è il motore predefinito da MySQL 5.5 (2010) e l’unico supportato attivamente. MyISAM è deprecato in MySQL 8.0.

CaratteristicaInnoDBMyISAM
LockingRow-levelTable-level
Transazioni ACIDSì (COMMIT, ROLLBACK)No
Crash recoveryAutomatico (redo log)REPAIR TABLE manuale
Scritture concorrentiEccellentiBloccanti
Foreign keySupportateNon supportate
Full-text searchSì (da MySQL 5.6)
StatoSviluppo attivoDeprecato (MySQL 8.0)
-- Trova tabelle ancora su MyISAM
SELECT TABLE_NAME, ENGINE
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND ENGINE = 'MyISAM';

-- Genera gli statement di conversione
SELECT CONCAT('ALTER TABLE `', TABLE_NAME, '` ENGINE=InnoDB;') AS conversion_sql
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND ENGINE = 'MyISAM';

Configurazione MySQL/MariaDB per WordPress

La configurazione di default di MySQL è pensata per un uso generico. Per WordPress serve un tuning specifico per workload read-heavy con scritture sporadiche. I parametri più impattanti, in ordine di priorità:

InnoDB buffer pool

Il singolo parametro più importante. Definisce la quantità di RAM dedicata al caching di dati e indici InnoDB. Su un server dedicato, assegnare il 70-80% della RAM. Su server condivisi (PHP + MySQL sulla stessa macchina), il 40-50%.

innodb_buffer_pool_size = 5G          -- server dedicato con 8 GB RAM
innodb_buffer_pool_instances = 5      -- un'istanza per GB di pool
innodb_log_file_size = 1G             -- 25% del buffer pool
innodb_flush_method = O_DIRECT        -- evita double buffering (Linux)

Verifica l’efficienza del buffer pool con:

SELECT
    ROUND(100 - (
        (SELECT VARIABLE_VALUE FROM performance_schema.global_status
         WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads') /
        (SELECT VARIABLE_VALUE FROM performance_schema.global_status
         WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests')
    * 100), 2) AS buffer_pool_hit_ratio_pct;

-- Il valore deve essere superiore al 99%

Query cache (solo MariaDB)

MySQL 8.0 ha rimosso la query cache perché creava contention sotto carichi con scritture concorrenti. MariaDB la mantiene e per WordPress con workload prevalentemente in lettura rimane utile:

-- Solo MariaDB
query_cache_type = 1
query_cache_size = 64M
query_cache_limit = 2M

Per MySQL 8.x, usa Redis o Memcached come object cache a livello applicativo.

Slow query log

Indispensabile per identificare le query problematiche. Ogni query che supera il tempo soglia viene registrata nel log:

slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = ON

Aggiornare URL in massa con SQL

Durante una migrazione di dominio o un cambio di protocollo (HTTP → HTTPS), è necessario aggiornare tutti i riferimenti interni nel database. Le tabelle coinvolte sono wp_options, wp_posts e wp_postmeta:

-- Aggiorna URL in wp_options
UPDATE wp_options
SET option_value = REPLACE(option_value, 'http://vecchio-dominio.com', 'https://nuovo-dominio.com')
WHERE option_name = 'home' OR option_name = 'siteurl';

-- Aggiorna URL nel contenuto dei post
UPDATE wp_posts
SET post_content = REPLACE(post_content, 'http://vecchio-dominio.com', 'https://nuovo-dominio.com')
WHERE post_content LIKE '%http://vecchio-dominio.com%';

-- Aggiorna URL nei GUID (identificatori permanenti)
UPDATE wp_posts
SET guid = REPLACE(guid, 'http://vecchio-dominio.com', 'https://nuovo-dominio.com')
WHERE guid LIKE '%http://vecchio-dominio.com%';

-- Aggiorna URL nei metadati
UPDATE wp_postmeta
SET meta_value = REPLACE(meta_value, 'http://vecchio-dominio.com', 'https://nuovo-dominio.com')
WHERE meta_value LIKE '%http://vecchio-dominio.com%';

Nota: per dati serializzati (array/oggetti PHP salvati come stringa), la funzione REPLACE() può corrompere la serializzazione perché altera la lunghezza della stringa senza aggiornare i contatori. Per quei casi serve uno script PHP dedicato o un tool come WP-CLI: wp search-replace 'vecchio-url' 'nuovo-url' --precise.

Calendario di manutenzione

OperazioneFrequenzaRischio
ANALYZE TABLE su tutte le tabelle WPSettimanaleNessuno
Pulizia transient scadutiSettimanaleBasso
Pulizia commenti spamSettimanaleNessuno
Verifica dimensione dati autoloadedMensileNessuno (diagnostica)
Pulizia postmeta orfaniMensileBasso (sempre backup)
Pulizia commentmeta orfaniMensileBasso
Revisione post revisionsMensileBasso
Analisi query lente con EXPLAINSu necessitàNessuno (diagnostica)
OPTIMIZE TABLESolo dopo pulizie massiveMedio (rebuild)
Verifica buffer pool hit ratioMensileNessuno (diagnostica)

Risorse e riferimenti

Articoli correlati

21 min lettura

Ridurre i tempi di risposta del server è vitale per abbattere il TTFB e dominare metriche come LCP e INP. Workflow tecnico per aumentare la velocità dell'hosting: dalla transizione verso VPS alla configurazione avanzata dello stack LEMP per ottenere server realmente accelerati.
33 mi piace

Autore

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Ultimi articoli aggiornati

16 min lettura

Metodologia operativa per la diagnosi di problemi su web server Linux tramite l'analisi dei log di sistema e applicativi. Il testo dettaglia l'ispezione di /var/log, l'interrogazione dei demoni con journalctl per monitorare lo stack LEMP e la configurazione di logrotate.
0 mi piace
21 min lettura

I crawler di Meta e Amazon generano milioni di richieste senza back-off: come quantificarli nei log, verificarne l'autenticità e fermarli con cache, robots.txt, rate limiting e WAF, senza perdere i link preview.
1 mi piace
22 min lettura

Difendere WordPress dai commenti spam con una strategia defense in depth a tre layer: configurazioni applicative, regole edge su Cloudflare, barriere a livello web server. Honeypot PHP, regole .htaccess e Nginx modernizzate, Cloudflare Turnstile, fail2ban. Snippet completi pronti da incollare.
0 mi piace
22 min lettura

Analisi tecnica della persistenza dei dati nel protocollo HTTP tramite header Set-Cookie. Comprendere la meccanica dei cookie, attributi come Max-Age e i limiti di Googlebot come crawler stateless è essenziale per diagnosticare problemi di rendering e involuntary cloaking.
4 mi piace
19 min lettura

Analisi dell'architettura RAG nativa per WordPress sviluppata interamente in PHP e MySQL, senza dipendenze da database vettoriali esterni. Il sistema supera i limiti della ricerca lessicale integrando la ricerca semantica su VPS o hosting condivisi con meno di 1GB di RAM.
3 mi piace

Richiedi un preventivo SEO e Google Ads

Porta il tuo sito web al livello successivo con l’esperienza di EVE Milano. La nostra agenzia di Search Marketing ha ricevuto oltre

User Access Addon Required

This shortcode requires the CF7 Database User Access addon to display data.

Please purchase and install the User Access addon to enable this feature.

Purchase User Access Addon

richieste di preventivo, un segnale chiaro della fiducia che imprenditori e manager, come te, ripongono nella nostra specializzazione tecnica e verticale nella SEO e PPC. Se la tua organizzazione cerca competenze specifiche per emergere nei risultati di Google, noi siamo pronti a fornire quel valore aggiunto. Richiedi un preventivo ora e scopri la differenza tra noi e gli altri.
Richiedi un preventivo

Vuoi ricevere un avviso al mese con le nuove guide pubblicate?

Iscriviti alla newsletter!