[{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/backup/","section":"Tags","summary":"","title":"Backup"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/categories/","section":"Categories","summary":"","title":"Categories"},{"content":" La differenza tra un sistema che funziona\ne uno che guida davvero il business non è fortuna.\nÈ comprensione profonda dei piani di esecuzione.\nÈ controllo dei privilegi e sicurezza dei dati.\nÈ progettazione dei dati orientata agli obiettivi aziendali.\nÈ performance che regge quando il carico cresce.\nI database sono il cuore operativo dell’ecosistema digitale di ogni azienda.\nSupportano processi critici, abilitano decisioni basate sui dati e determinano velocità ed efficienza operativa.\nDentro il Motore è lo spazio in cui analizzo ciò che accade sotto il cofano di PostgreSQL, Oracle e MySQL: performance tuning, sicurezza, architettura e scelte tecniche applicabili in ambienti reali.\nPerché nel mondo data-driven di oggi i database non sono semplici componenti software.\nSono asset strategici che influenzano competitività, affidabilità e crescita sostenibile.\n","date":null,"permalink":"https://ivanluminaria.com/it/posts/","section":"Database Strategy","summary":"\u003cblockquote\u003e\n\u003cp\u003eLa differenza tra un sistema che funziona\u003cbr\u003e\ne uno che guida davvero il business non è fortuna.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eÈ comprensione profonda dei piani di esecuzione.\u003cbr\u003e\nÈ controllo dei privilegi e sicurezza dei dati.\u003cbr\u003e\nÈ progettazione dei dati orientata agli obiettivi aziendali.\u003cbr\u003e\nÈ performance che regge quando il carico cresce.\u003cbr\u003e\u003c/p\u003e\n\u003cp\u003eI database sono il cuore operativo dell’ecosistema digitale di ogni azienda.\u003cbr\u003e\nSupportano processi critici, abilitano decisioni basate sui dati e determinano velocità ed efficienza operativa.\u003cbr\u003e\u003c/p\u003e","title":"Database Strategy"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/","section":"Ivan Luminaria","summary":"","title":"Ivan Luminaria"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/mariadb/","section":"Tags","summary":"","title":"Mariadb"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/mydumper/","section":"Tags","summary":"","title":"Mydumper"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/categories/mysql/","section":"Categories","summary":"","title":"Mysql"},{"content":"MySQL è il database che non ha bisogno di presentazioni.\nÈ il motore che ha alimentato la crescita del web per oltre vent\u0026rsquo;anni.\nNato nel 1995 in Svezia, nel 2008 fu acquisito da Sun Microsystems — e quando nel 2010 Oracle completò l\u0026rsquo;acquisizione di Sun, MySQL finì nel portafoglio del più grande vendor di database commerciali al mondo. Ero dipendente Oracle in quel periodo, e ricordo bene il clima: da un lato la curiosità di vedere come Oracle avrebbe gestito un prodotto open source così popolare, dall\u0026rsquo;altro il timore che MySQL venisse marginalizzato a favore del database proprietario.\nQuel timore spinse Michael \u0026ldquo;Monty\u0026rdquo; Widenius — il creatore originale di MySQL — a fare il fork nel 2009, dando vita a MariaDB. Un progetto che condivide le radici con MySQL ma ha preso strade proprie su storage engine, ottimizzatore e funzionalità avanzate.\nLa storia ha dimostrato che entrambi i progetti sono sopravvissuti e si sono evoluti, ma le scelte architetturali divergono sempre di più. Conoscere le differenze non è accademia — è necessità operativa.\nIn questa sezione esploro MySQL e MariaDB dal punto di vista operativo: sicurezza, gestione utenti, performance e scelte progettuali che fanno la differenza in ambienti di produzione.\nPerché usare MySQL non significa solo lanciare query.\nSignifica capire come il motore gestisce connessioni, privilegi e risorse sotto carico reale.\n","date":null,"permalink":"https://ivanluminaria.com/it/posts/mysql/","section":"Database Strategy","summary":"\u003cp\u003eMySQL è il database che non ha bisogno di presentazioni.\u003cbr\u003e\nÈ il motore che ha alimentato la crescita del web per oltre vent\u0026rsquo;anni.\u003cbr\u003e\u003c/p\u003e\n\u003cp\u003eNato nel 1995 in Svezia, nel 2008 fu acquisito da Sun Microsystems — e quando nel 2010 Oracle completò l\u0026rsquo;acquisizione di Sun, MySQL finì nel portafoglio del più grande vendor di database commerciali al mondo. Ero dipendente Oracle in quel periodo, e ricordo bene il clima: da un lato la curiosità di vedere come Oracle avrebbe gestito un prodotto open source così popolare, dall\u0026rsquo;altro il timore che MySQL venisse marginalizzato a favore del database proprietario.\u003cbr\u003e\u003c/p\u003e","title":"MySQL"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/mysqldump/","section":"Tags","summary":"","title":"Mysqldump"},{"content":"La chiamata è arrivata un venerdì pomeriggio — perché queste cose succedono sempre di venerdì. Il DBA di un cliente nel settore logistico mi scrive su Teams: \u0026ldquo;Il backup notturno ha impiegato tre ore e mezza. Stamattina gli utenti si sono trovati l\u0026rsquo;applicazione lenta alle 8. Possiamo parlarne?\u0026rdquo;\nPotevamo parlarne, sì. Anzi, dovevamo parlarne da un pezzo.\nIl setup era un classico: un MySQL 8.0 su Rocky Linux, database da circa 60 GB, un gestionale con una trentina di tabelle InnoDB di cui quattro o cinque davvero grosse — la tabella degli ordini, quella dei movimenti di magazzino, la storicizzazione dei tracking. Il backup veniva fatto ogni notte con un mysqldump lanciato da cron alle 2:00. Aveva funzionato per anni. Il problema è che il database nel frattempo era cresciuto.\nTre ore di mysqldump significano tre ore di --lock-all-tables — o nel migliore dei casi tre ore di transazione consistente con --single-transaction che comunque tiene aperta una snapshot InnoDB per tutto il tempo. E quando il dump finisce alle 5:00 e il restore di test (che nessuno faceva) avrebbe richiesto altre quattro ore, la finestra di backup semplicemente non esiste più.\nIl problema vero: mysqldump è single-threaded #La prima cosa da capire su mysqldump è che fa una cosa sola alla volta. Una tabella dopo l\u0026rsquo;altra, una riga dopo l\u0026rsquo;altra, un file SQL in output. Punto.\nNon c\u0026rsquo;è parallelismo. Non c\u0026rsquo;è compressione nativa. Non c\u0026rsquo;è modo di dire \u0026ldquo;usa 4 thread e fai prima\u0026rdquo;. È un programma nato nel 2000 — letteralmente — e il suo design riflette un\u0026rsquo;epoca in cui 60 GB erano una quantità impensabile per un database MySQL.\nIl dump del cliente produceva un file SQL da 45 GB. Un singolo file monolitico che conteneva tutte le tabelle, tutte le stored procedure, tutti i trigger. Per fare un restore bastava dare in pasto quel file a mysql — ma ci volevano quattro ore, perché anche il restore è sequenziale.\n# Il backup classico — funziona, ma scala malissimo mysqldump --single-transaction --routines --triggers --events \\ --all-databases \u0026gt; /backup/full_backup.sql La cosa paradossale è che mysqldump ha un vantaggio enorme: è ovunque. È incluso in ogni installazione MySQL, non richiede nulla di aggiuntivo, produce SQL leggibile. Se devi spostare una tabellina da 500 righe tra due ambienti, è perfetto. Se devi fare il backup di un database da 60 GB in produzione — no.\nHo spiegato al cliente che avevamo due alternative: mysqlpump e mydumper. Due strumenti con filosofie diverse, limiti diversi, e performance che sulla carta promettono molto ma che nella realtà vanno testate.\nmysqlpump: la promessa non mantenuta di Oracle #mysqlpump è arrivato con MySQL 5.7 come evoluzione ufficiale di mysqldump. La promessa era chiara: parallelismo nel dump, compressione nativa, gestione degli utenti. Sulla carta, tutto quello che mancava a mysqldump.\nL\u0026rsquo;ho installato — anzi, era già lì perché è incluso nella distribuzione MySQL — e ho lanciato un primo test sul database del cliente:\nmysqlpump --single-transaction --default-parallelism=4 \\ --compress-output=zlib --all-databases \u0026gt; /backup/full_backup.sql.zlib Il risultato? 48 minuti per il dump, contro le tre ore e mezza di mysqldump. Un miglioramento importante. Ma poi ho guardato meglio.\nIl parallelismo di mysqlpump funziona a livello di tabella: se hai 4 thread, dumpa 4 tabelle contemporaneamente. Il problema è che quando hai una tabella da 30 GB e tre tabelle da 50 MB, tre thread finiscono in trenta secondi e poi un thread solo si trascina per quaranta minuti sulla tabella grande. Il parallelismo è tanto efficace quanto bilanciato è il tuo database — e i database di produzione non sono mai bilanciati.\nMa il problema più serio è un altro. mysqlpump con --single-transaction non garantisce un backup consistente tra tabelle diverse. Lo dice la documentazione stessa, in una nota che la maggior parte delle persone non legge:\nmysqlpump does not guarantee consistency of the dumped data across tables when using parallelism. Tables dumped in different threads may be at different points in time.\nRileggete questa frase. Se usi il parallelismo — che è l\u0026rsquo;unico motivo per usare mysqlpump — perdi la garanzia di consistenza tra tabelle. In un database relazionale. Dove le tabelle hanno foreign key tra di loro.\nPer un ambiente di sviluppo o test, può andare bene. Per un backup di produzione da cui potresti dover fare un restore in caso di disastro? No. Assolutamente no.\nUn\u0026rsquo;altra nota: Oracle ha dichiarato mysqlpump deprecato in MySQL 8.0.34 e lo ha rimosso in MySQL 8.4. Il che la dice lunga sulla fiducia che Oracle stessa aveva in questo strumento.\nmydumper: il tool che fa quello che promette #mydumper è un progetto open source nato nel 2009 dalla comunità MySQL — in particolare dal lavoro di Domas Mituzas, Andrew Hutchings e poi mantenuto da Max Bubenick. Non è un tool Oracle. Non è incluso nella distribuzione MySQL. Va installato separatamente. Ma fa una cosa che né mysqldump né mysqlpump fanno: parallelismo vero, a livello di chunk all\u0026rsquo;interno della stessa tabella.\n# Installazione su Rocky Linux / CentOS yum install https://github.com/mydumper/mydumper/releases/download/v0.16.9-1/mydumper-0.16.9-1.el8.x86_64.rpm mydumper prende una tabella grande, la divide in chunk (per default basandosi sulla primary key), e assegna ogni chunk a un thread diverso. Quindi quella tabella da 30 GB non viene dumpata da un singolo thread — viene spezzata in pezzi e scaricata in parallelo.\nIl dump che ho lanciato sul database del cliente:\nmydumper --threads 8 --compress --trx-consistency-only \\ --outputdir /backup/mydumper_full/ \\ --logfile /var/log/mydumper.log 22 minuti. Contro le tre ore e mezza di mysqldump e i 48 minuti di mysqlpump.\nMa il vero vantaggio di mydumper non è solo la velocità del dump — è la velocità del restore. mydumper produce un file per ogni tabella (o per ogni chunk), e il suo compagno myloader li carica in parallelo:\nmyloader --threads 8 --directory /backup/mydumper_full/ \\ --overwrite-tables --compress-protocol Il restore che con mysqldump avrebbe richiesto quattro ore, con myloader ne ha richieste una e venti. Su un database da 60 GB. Con otto thread.\nI numeri: test su ambiente reale #Ho fatto i test sullo stesso server del cliente — non su un ambiente di laboratorio con dischi NVMe e RAM infinita. Server reale, carico reale, dischi SATA in RAID 10.\nOperazione mysqldump mysqlpump (4 thread) mydumper (8 thread) Dump 3h 25min 48 min 22 min Dimensione output 45 GB (SQL) 12 GB (compresso) 9.8 GB (compresso) Restore ~4h (stimato) ~3h (stimato) 1h 20min Consistenza tra tabelle Sì No (con parallelismo) Sì Lock sulle scritture No* No* No* *Con --single-transaction su InnoDB.\nQualche nota sui numeri:\nIl restore di mysqldump e mysqlpump è stimato perché non ho fatto il test completo in produzione — troppo rischioso. I tempi sono calcolati da test parziali su un subset delle tabelle La compressione di mydumper (--compress) usa zstd di default, che comprime meglio e più velocemente di zlib Il restore con myloader disabilita i check delle foreign key e ricostruisce gli indici alla fine, il che accelera enormemente il caricamento Le opzioni critiche che non devi dimenticare #Qualunque strumento tu scelga, ci sono opzioni che devi includere sempre. Le ho viste dimenticate troppe volte, con conseguenze che vanno dal fastidio al disastro.\n\u0026ndash;single-transaction #Obbligatorio su InnoDB. Senza questa opzione, il dump acquisisce lock che bloccano le scritture. Con --single-transaction, il dump usa una transazione con isolation level REPEATABLE READ per ottenere una snapshot consistente senza bloccare nessuno.\nAttenzione: funziona solo su tabelle InnoDB. Se hai tabelle MyISAM (e sì, nel 2026 ne trovo ancora), quelle verranno comunque lockate.\n\u0026ndash;routines \u0026ndash;triggers \u0026ndash;events #Stored procedure, trigger e scheduled events non vengono inclusi nel dump di default. Li devi chiedere esplicitamente. Ho visto restore che \u0026ldquo;funzionavano perfettamente\u0026rdquo; — tranne che mancavano tutti i trigger di audit e l\u0026rsquo;applicazione scriveva dati senza tracciamento.\n\u0026ndash;set-gtid-purged (MySQL) o \u0026ndash;gtid (mydumper) #Se usi la replica basata su GTID — e dovresti — il dump deve gestire correttamente i GTID. Se non lo fa, il restore su uno slave genera conflitti di replica che ti faranno impazzire.\nVerifica del restore #Questa non è un\u0026rsquo;opzione — è una pratica. Il backup che non verifichi è il backup che non hai. Ho un cliente che faceva backup ogni notte da tre anni. Il giorno che ha dovuto fare un restore, ha scoperto che il file era corrotto dalla settimana prima. Tre anni di backup, nessun test di restore.\n# Verifica minima con mydumper: restore su istanza di test myloader --threads 4 --directory /backup/mydumper_full/ \\ --host test-mysql-server --overwrite-tables # Conta le righe delle tabelle principali mysql -h test-mysql-server -e \u0026#34; SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema = \u0026#39;production_db\u0026#39; ORDER BY table_rows DESC LIMIT 10;\u0026#34; Quando usare cosa #Dopo trent\u0026rsquo;anni di database, la mia regola è semplice:\nmysqldump — per database sotto i 5 GB, per migrazioni una tantum, per dump di singole tabelle, per ambienti di sviluppo dove la velocità non è critica. È il coltellino svizzero: fa tutto, lentamente, ma lo fa.\nmysqlpump — non lo consiglio più. Deprecato da Oracle, consistenza non garantita con il parallelismo, e mydumper fa tutto quello che mysqlpump prometteva ma meglio. Se lo stai usando, pianifica la migrazione a mydumper.\nmydumper/myloader — per qualsiasi database sopra i 10 GB in produzione. Il parallelismo vero, la consistenza garantita, il restore veloce. Richiede un\u0026rsquo;installazione separata, ma il tempo che risparmi al primo backup ripaga abbondantemente.\nLa strategia completa: non solo logical backup #Una cosa che dico sempre ai clienti: il logical backup (mysqldump, mydumper) è una componente della strategia, non la strategia intera.\nPer il cliente della logistica abbiamo messo in piedi questo schema:\nmydumper ogni notte — backup logico completo, 8 thread, compressione zstd, retention 7 giorni Binary log continuo — con binlog_expire_logs_seconds a 7 giorni, per il point-in-time recovery Percona XtraBackup settimanale — backup fisico a caldo, per il restore più veloce possibile in caso di disastro totale Test di restore automatico — uno script che ogni domenica fa il restore del backup di mydumper su un\u0026rsquo;istanza di test e verifica il conteggio delle righe Il backup logico è comodo perché è portabile — puoi fare il restore su qualsiasi versione di MySQL, su qualsiasi architettura. Ma per un database da 60 GB, un backup fisico con XtraBackup ti permette un restore in 15-20 minuti invece di un\u0026rsquo;ora e mezza. Quando il database di produzione è giù e il telefono squilla, quell\u0026rsquo;ora di differenza conta.\nIl venerdì successivo, il DBA del cliente mi ha scritto di nuovo su Teams. Ma questa volta il messaggio era diverso: \u0026ldquo;Backup finito in 23 minuti. Nessun impatto sugli utenti. Grazie.\u0026rdquo;\nNon c\u0026rsquo;è di che. Ma la prossima volta, non aspettare che il backup ci metta tre ore per chiedermi aiuto.\nGlossario #mysqldump — Utility di backup logico inclusa in ogni installazione MySQL. Produce un file SQL sequenziale con tutte le istruzioni per ricreare schema e dati. Single-threaded, affidabile ma lenta su database grandi.\nmysqlpump — Evoluzione di mysqldump introdotta in MySQL 5.7, con supporto per il parallelismo a livello di tabella e compressione nativa. Deprecato da Oracle in MySQL 8.0.34 per problemi di consistenza.\nmydumper — Tool open source di backup logico per MySQL/MariaDB con parallelismo reale a livello di chunk. Divide le tabelle grandi in pezzi e li esporta con thread multipli, con restore parallelo tramite myloader.\nPITR — Point-in-Time Recovery: tecnica che combina un backup completo con i binary log per riportare il database a un qualsiasi momento nel tempo, non solo all\u0026rsquo;ora del backup.\nGTID — Global Transaction Identifier: identificativo univoco assegnato a ogni transazione in MySQL, che semplifica la gestione della replica e il tracking delle transazioni tra master e slave.\n","date":"14 aprile 2026","permalink":"https://ivanluminaria.com/it/posts/mysql/mysqldump-mysqlpump-mydumper/","section":"Database Strategy","summary":"\u003cp\u003eLa chiamata è arrivata un venerdì pomeriggio — perché queste cose succedono sempre di venerdì. Il DBA di un cliente nel settore logistico mi scrive su Teams: \u0026ldquo;Il backup notturno ha impiegato tre ore e mezza. Stamattina gli utenti si sono trovati l\u0026rsquo;applicazione lenta alle 8. Possiamo parlarne?\u0026rdquo;\u003c/p\u003e\n\u003cp\u003ePotevamo parlarne, sì. Anzi, dovevamo parlarne da un pezzo.\u003c/p\u003e\n\u003cp\u003eIl setup era un classico: un MySQL 8.0 su Rocky Linux, database da circa 60 GB, un gestionale con una trentina di tabelle InnoDB di cui quattro o cinque davvero grosse — la tabella degli ordini, quella dei movimenti di magazzino, la storicizzazione dei tracking. Il backup veniva fatto ogni notte con un mysqldump lanciato da cron alle 2:00. Aveva funzionato per anni. Il problema è che il database nel frattempo era cresciuto.\u003c/p\u003e","title":"mysqldump vs mysqlpump vs mydumper: il backup che non ti fa dormire la notte"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/restore/","section":"Tags","summary":"","title":"Restore"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/","section":"Tags","summary":"","title":"Tags"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/categories/data-warehouse/","section":"Categories","summary":"","title":"Data Warehouse"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/data-warehouse/","section":"Tags","summary":"","title":"Data-Warehouse"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/fact-table/","section":"Tags","summary":"","title":"Fact-Table"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/oracle/","section":"Tags","summary":"","title":"Oracle"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/partitioning/","section":"Tags","summary":"","title":"Partitioning"},{"content":"La settimana scorsa un collega mi ha raccontato di un progetto dove le query sul data warehouse avevano smesso di tornare in tempi ragionevoli. \u0026ldquo;Quanto ci mette il report trimestrale?\u0026rdquo; gli ho chiesto. \u0026ldquo;Dodici minuti.\u0026rdquo; \u0026ldquo;E prima?\u0026rdquo; \u0026ldquo;Un minuto e mezzo.\u0026rdquo;\nNon ho dovuto chiedere altro. Conoscevo già il copione.\nUna fact table che parte piccola, cresce ogni giorno, e nessuno si preoccupa della struttura fisica finché un giorno le query non tornano più. Non è un bug, non è un errore di codice. È il peso dei dati che alla fine si fa sentire.\nIl contesto: GDO e tre anni di scontrini #Il progetto era nel settore della grande distribuzione organizzata — una catena di supermercati con circa duecento punti vendita, un centinaio di milioni di euro di fatturato annuo, e un data warehouse Oracle 19c che raccoglieva tutto: vendite, resi, movimenti di magazzino, promozioni.\nLa tabella al centro del problema si chiamava FACT_VENDITE. Ogni riga era una riga di scontrino — uno scontrino medio ha otto righe, moltiplicato per trentamila scontrini al giorno su duecento negozi, fa circa 48 milioni di righe al mese. In tre anni si erano accumulate 800 milioni di righe.\nLa struttura era questa:\nCREATE TABLE fact_vendite ( vendita_id NUMBER(18) NOT NULL, data_vendita DATE NOT NULL, punto_vendita_id NUMBER(10) NOT NULL, prodotto_id NUMBER(10) NOT NULL, cliente_id NUMBER(10), quantita NUMBER(10,2) NOT NULL, importo NUMBER(12,2) NOT NULL, sconto NUMBER(8,2) DEFAULT 0, tipo_pagamento VARCHAR2(20), CONSTRAINT pk_fact_vendite PRIMARY KEY (vendita_id) ); Un unico indice sulla primary key, un indice su data_vendita e uno composito su (punto_vendita_id, data_vendita). Nessun partizionamento. Otto centinaia di milioni di righe in un\u0026rsquo;unica tabella monolitica.\n🔍 Il sintomo: full table scan su 800 milioni di righe #Le query analitiche del DWH lavoravano quasi sempre per periodo. Vendite dell\u0026rsquo;ultimo trimestre per punto vendita. Confronto anno su anno per categoria merceologica. Margini mensili per regione. Tutte query con un filtro su data_vendita.\nIl report trimestrale era questo:\nSELECT pv.regione, cat.famiglia, SUM(f.importo) AS fatturato, SUM(f.quantita) AS pezzi_venduti, SUM(f.sconto) AS sconto_totale FROM fact_vendite f JOIN dim_punto_vendita pv ON f.punto_vendita_id = pv.punto_vendita_id JOIN dim_prodotto cat ON f.prodotto_id = cat.prodotto_id WHERE f.data_vendita BETWEEN DATE \u0026#39;2025-10-01\u0026#39; AND DATE \u0026#39;2025-12-31\u0026#39; GROUP BY pv.regione, cat.famiglia ORDER BY fatturato DESC; Il predicato su data_vendita avrebbe dovuto usare l\u0026rsquo;indice. E in effetti lo usava — un anno prima, quando la tabella aveva 500 milioni di righe. Ma con 800 milioni, l\u0026rsquo;optimizer aveva deciso che l\u0026rsquo;indice non conveniva più. Il calcolo era semplice: un trimestre = circa il 8% delle righe totali. Con un index range scan, Oracle avrebbe dovuto fare 64 milioni di accessi random ai blocchi dati. Un full table scan sequenziale costava meno.\nE così faceva: leggeva 800 milioni di righe per restituirne 64 milioni.\n-------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | -------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1200 | 84K | | 1 | SORT GROUP BY | | 1200 | 84K | |* 2 | HASH JOIN | | 64M | 4480M | | 3 | TABLE ACCESS FULL| DIM_PRODOTTO | 12K | 168K | |* 4 | HASH JOIN | | 64M | 3520M | | 5 | TABLE ACCESS FULL| DIM_PUNTO_VENDITA | 200 | 4000 | |* 6 | TABLE ACCESS FULL| FACT_VENDITE| 800M | 40G | -------------------------------------------------------------- Quaranta gigabyte di I/O per una query trimestrale. In un ambiente dove il buffer pool era dimensionato a 16 GB, significava leggere più di due volte l\u0026rsquo;intero cache da disco. Dodici minuti.\n🏗️ La soluzione: range partitioning per mese #Il partizionamento range per data è la scelta naturale per una fact table in un data warehouse. I dati entrano in ordine cronologico, le query filtrano per periodo, i dati vecchi diventano freddi e quelli nuovi caldi. La data è la chiave di partizionamento perfetta.\nHo scelto il partizionamento mensile — 36 partizioni per tre anni di storico, più una partizione per i dati correnti. Ogni partizione conteneva circa 48 milioni di righe: un volume gestibile per le query e per le operazioni di manutenzione.\nCREATE TABLE fact_vendite_part ( vendita_id NUMBER(18) NOT NULL, data_vendita DATE NOT NULL, punto_vendita_id NUMBER(10) NOT NULL, prodotto_id NUMBER(10) NOT NULL, cliente_id NUMBER(10), quantita NUMBER(10,2) NOT NULL, importo NUMBER(12,2) NOT NULL, sconto NUMBER(8,2) DEFAULT 0, tipo_pagamento VARCHAR2(20) ) PARTITION BY RANGE (data_vendita) ( PARTITION p_2023_01 VALUES LESS THAN (DATE \u0026#39;2023-02-01\u0026#39;), PARTITION p_2023_02 VALUES LESS THAN (DATE \u0026#39;2023-03-01\u0026#39;), PARTITION p_2023_03 VALUES LESS THAN (DATE \u0026#39;2023-04-01\u0026#39;), -- ... 33 partizioni intermedie ... PARTITION p_2025_12 VALUES LESS THAN (DATE \u0026#39;2026-01-01\u0026#39;), PARTITION p_max VALUES LESS THAN (MAXVALUE) ); Con un indice locale sulla data:\nCREATE INDEX idx_vendite_data_local ON fact_vendite_part (data_vendita) LOCAL; CREATE INDEX idx_vendite_pv_local ON fact_vendite_part (punto_vendita_id, data_vendita) LOCAL; Ogni partizione ha il suo segmento di indice. Quando l\u0026rsquo;optimizer elimina una partizione, elimina anche il segmento di indice corrispondente.\n📦 La migrazione: da monolite a partizioni #Migrare 800 milioni di righe non è un\u0026rsquo;operazione che si fa con un semplice INSERT\u0026hellip;SELECT. Serve una strategia.\nHo usato l\u0026rsquo;approccio CTAS (Create Table As Select) con NOLOGGING e parallelismo. La procedura era:\nCreare la tabella partizionata vuota con la struttura definitiva Popolarla con un INSERT diretto dalla tabella originale Ricostruire gli indici Validare i conteggi Rinominare le tabelle (swap) Fare un backup RMAN immediato (NOLOGGING richiede backup) ALTER SESSION ENABLE PARALLEL DML; INSERT /*+ APPEND PARALLEL(8) */ INTO fact_vendite_part SELECT * FROM fact_vendite; COMMIT; Con 8 processi paralleli e NOLOGGING, il caricamento ha impiegato 47 minuti per 800 milioni di righe. Non male, considerando che ogni riga doveva essere distribuita nella partizione corretta in base alla data.\nPoi la fase di validazione:\nSELECT \u0026#39;Originale\u0026#39; AS fonte, COUNT(*) AS righe FROM fact_vendite UNION ALL SELECT \u0026#39;Partizionata\u0026#39;, COUNT(*) FROM fact_vendite_part; 800.247.331 righe da entrambe le parti. Perfetto.\nALTER TABLE fact_vendite RENAME TO fact_vendite_old; ALTER TABLE fact_vendite_part RENAME TO fact_vendite; La tabella originale l\u0026rsquo;ho tenuta per una settimana come rete di sicurezza, poi l\u0026rsquo;ho droppata.\n⚡ Il partition pruning in azione #Con il partizionamento in posizione, la stessa query trimestrale di prima cambiava completamente execution plan:\nSELECT pv.regione, cat.famiglia, SUM(f.importo) AS fatturato, SUM(f.quantita) AS pezzi_venduti, SUM(f.sconto) AS sconto_totale FROM fact_vendite f JOIN dim_punto_vendita pv ON f.punto_vendita_id = pv.punto_vendita_id JOIN dim_prodotto cat ON f.prodotto_id = cat.prodotto_id WHERE f.data_vendita BETWEEN DATE \u0026#39;2025-10-01\u0026#39; AND DATE \u0026#39;2025-12-31\u0026#39; GROUP BY pv.regione, cat.famiglia ORDER BY fatturato DESC; ---------------------------------------------------------------------- | Id | Operation | Name | Pstart | Pstop | ---------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | 1 | SORT GROUP BY | | | | |* 2 | HASH JOIN | | | | | 3 | TABLE ACCESS FULL | DIM_PRODOTTO | | | |* 4 | HASH JOIN | | | | | 5 | TABLE ACCESS FULL | DIM_PUNTO_V | | | | 6 | PARTITION RANGE ITERATOR| | 34 | 36 | |* 7 | TABLE ACCESS FULL | FACT_VENDITE | 34 | 36 | ---------------------------------------------------------------------- Pstart: 34, Pstop: 36. L\u0026rsquo;optimizer leggeva solo tre partizioni su 37 — ottobre, novembre e dicembre 2025. Invece di 800 milioni di righe, ne scansionava 144 milioni. Invece di 40 GB di I/O, circa 7 GB.\nIl risultato? Da 12 minuti a 40 secondi.\nNon perché l\u0026rsquo;hardware fosse più veloce, non perché avessi riscritto le query. Solo perché il database adesso sapeva dove non cercare.\n🔄 Exchange partition: il caricamento che non costa nulla #In un data warehouse, i dati arrivano con una cadenza regolare — nel nostro caso, un ETL notturno che caricava le vendite del giorno. Il problema classico del partizionamento è: come carichi i nuovi dati nella partizione corretta senza impattare le query?\nLa risposta si chiama exchange partition .\nIl processo funzionava così:\nL\u0026rsquo;ETL carica i dati della giornata in una tabella di staging non partizionata Si costruiscono gli indici sulla staging table (stessa struttura degli indici locali) Si esegue l\u0026rsquo;exchange partition: la staging table e la partizione target si scambiano i segmenti -- 1. Tabella di staging con stessa struttura della partizione CREATE TABLE stg_vendite_daily ( vendita_id NUMBER(18) NOT NULL, data_vendita DATE NOT NULL, punto_vendita_id NUMBER(10) NOT NULL, prodotto_id NUMBER(10) NOT NULL, cliente_id NUMBER(10), quantita NUMBER(10,2) NOT NULL, importo NUMBER(12,2) NOT NULL, sconto NUMBER(8,2) DEFAULT 0, tipo_pagamento VARCHAR2(20) ); -- 2. Caricamento ETL nella staging (operazione indipendente) INSERT /*+ APPEND */ INTO stg_vendite_daily SELECT * FROM source_vendite WHERE data_vendita = TRUNC(SYSDATE - 1); -- 3. Exchange: swap istantaneo dei segmenti ALTER TABLE fact_vendite EXCHANGE PARTITION p_2026_01 WITH TABLE stg_vendite_daily INCLUDING INDEXES WITHOUT VALIDATION; L\u0026rsquo;exchange partition è un\u0026rsquo;operazione DDL che modifica solo il data dictionary — non sposta nemmeno un byte di dati. Ci mette meno di un secondo, indipendentemente dal volume. E durante l\u0026rsquo;exchange, le query sulle altre partizioni continuano a funzionare senza interruzione.\nNel nostro caso, l\u0026rsquo;ETL notturno accumulava i dati della giornata nella staging, e a fine mese si faceva l\u0026rsquo;exchange con la partizione del mese corrente. Durante il mese, i dati giornalieri andavano nella partizione p_max (la catch-all) e poi venivano consolidati con un exchange mensile.\n📊 Il ciclo di vita dei dati #Con il partizionamento la gestione del ciclo di vita diventa banale. Dopo tre anni, la partizione più vecchia si può:\ncomprimere: ALTER TABLE fact_vendite MODIFY PARTITION p_2023_01 COMPRESS FOR QUERY HIGH; spostare su storage più lento: ALTER TABLE fact_vendite MOVE PARTITION p_2023_01 TABLESPACE ts_archivio; eliminare direttamente: ALTER TABLE fact_vendite DROP PARTITION p_2023_01; Droppare una partizione è istantaneo — è un\u0026rsquo;operazione sul data dictionary, non cancella riga per riga. Confrontalo con un DELETE FROM fact_vendite WHERE data_vendita \u0026lt; DATE '2023-02-01' su 48 milioni di righe: minuti di elaborazione, tonnellate di redo log, e una tabella piena di spazio recuperabile che richiede un reorganize.\nNel progetto GDO, la policy era: 3 anni online compressi, poi drop. Ogni primo del mese un job schedulato creava la nuova partizione e, se necessario, droppava quella di 37 mesi prima. Completamente automatico.\n🎯 Quello che il partizionamento non risolve #Il partizionamento non è una bacchetta magica. Non sostituisce gli indici — se la query non filtra per la chiave di partizionamento, il pruning non si attiva e il database legge tutte le partizioni. Non migliora le query che già usano un indice efficiente su poche righe. E aggiunge complessità nella gestione: partizioni da creare, monitorare, comprimere, eliminare.\nMa per una fact table in un data warehouse — dove i dati sono cronologici, le query filtrano per periodo, e i volumi crescono ogni giorno — il partizionamento range per data non è un\u0026rsquo;opzione. È un requisito architetturale.\nIl collega con il report da 12 minuti non aveva un problema di hardware o di query mal scritte. Aveva una tabella che era cresciuta oltre il punto in cui la mancanza di struttura fisica diventa un collo di bottiglia. Il partizionamento ha rimesso le cose al loro posto: 40 secondi, e nessuna riga letta inutilmente.\nGlossario #Range Partitioning — Strategia di partizionamento che divide una tabella in segmenti basati su intervalli di valori di una colonna (tipicamente una data). Ogni partizione contiene le righe il cui valore cade nell\u0026rsquo;intervallo definito.\nExchange Partition — Operazione DDL Oracle che scambia istantaneamente i segmenti dati tra una tabella non partizionata e una partizione, senza spostare fisicamente i dati. Usata nei data warehouse per caricamenti bulk a impatto zero.\nPartition Pruning — Meccanismo automatico dell\u0026rsquo;optimizer Oracle che esclude le partizioni non rilevanti durante l\u0026rsquo;esecuzione di una query, leggendo solo quelle corrispondenti al predicato WHERE.\nFact table — Tabella centrale dello star schema che contiene le misure numeriche del business (importi, quantità, conteggi) e le chiavi esterne verso le tabelle dimensionali.\nFull Table Scan — Operazione di lettura in cui il database percorre tutti i blocchi di una tabella senza utilizzare indici. Efficiente su grandi volumi quando la selettività è bassa, costoso quando si cercano poche righe.\n","date":"7 aprile 2026","permalink":"https://ivanluminaria.com/it/posts/data-warehouse/partitioning-dwh/","section":"Database Strategy","summary":"\u003cp\u003eLa settimana scorsa un collega mi ha raccontato di un progetto dove le query sul data warehouse avevano smesso di tornare in tempi ragionevoli. \u0026ldquo;Quanto ci mette il report trimestrale?\u0026rdquo; gli ho chiesto. \u0026ldquo;Dodici minuti.\u0026rdquo; \u0026ldquo;E prima?\u0026rdquo; \u0026ldquo;Un minuto e mezzo.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eNon ho dovuto chiedere altro. Conoscevo già il copione.\u003c/p\u003e\n\u003cp\u003eUna \u003cspan class=\"glossary-tip\" tabindex=\"0\" data-glossary-desc=\"Tabella centrale dello star schema che contiene le misure numeriche e le chiavi esterne verso le tabelle dimensionali.\" data-glossary-url=\"/it/glossary/fact-table/\" data-glossary-more=\"Leggi di più →\"\u003efact table\u003c/span\u003e\n che parte piccola, cresce ogni giorno, e nessuno si preoccupa della struttura fisica finché un giorno le query non tornano più. Non è un bug, non è un errore di codice. È il peso dei dati che alla fine si fa sentire.\u003c/p\u003e","title":"Partitioning nel DWH: quando 3 anni di dati pesano troppo"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/performance/","section":"Tags","summary":"","title":"Performance"},{"content":"Il messaggio nel canale Slack del team infrastruttura era di quelli che fanno alzare la testa dallo schermo: \u0026ldquo;Disco al 95% sul db di produzione. Chi può guardare?\u0026rdquo;\nIl server era un MySQL 8.0 su Rocky Linux, un gestionale usato da un centinaio di utenti. Il database in sé occupava circa 40 GB — niente di straordinario. Ma nella directory dei dati c\u0026rsquo;erano 180 GB di binary log. Sei mesi di binlog che nessuno aveva mai pensato di gestire.\nNon è la prima volta che vedo questa scena. Anzi, direi che è uno dei pattern più ricorrenti nei ticket che mi arrivano. Il binary log è una di quelle funzionalità di MySQL che funzionano in silenzio, senza chiedere nulla — finché il disco non si riempie.\nCosa sono i binary log, in pratica #Il binary log è un registro sequenziale di tutti gli eventi che modificano i dati nel database. Ogni INSERT, UPDATE, DELETE, ogni DDL — tutto viene scritto in file binari numerati progressivamente: mysql-bin.000001, mysql-bin.000002 e così via.\nIl nome inganna un po\u0026rsquo;. Non è un \u0026ldquo;log\u0026rdquo; nel senso del syslog o dell\u0026rsquo;error log — non è fatto per essere letto da un umano. È un flusso binario strutturato che MySQL usa internamente per due scopi fondamentali:\nReplica: lo slave legge i binlog del master per replicare le stesse operazioni Point-in-time recovery (PITR) : dopo un restore da backup, puoi \u0026ldquo;riapplicare\u0026rdquo; i binlog per portare i dati fino a un momento preciso Senza il binary log, non puoi fare né l\u0026rsquo;una né l\u0026rsquo;altra cosa. Questa è la ragione per cui il primo istinto — \u0026ldquo;disabilitiamo i binlog così non riempiono il disco\u0026rdquo; — è quasi sempre sbagliato.\nCome MySQL genera i binlog #Il binary logging si attiva con il parametro log_bin. Da MySQL 8.0 è abilitato di default — un cambio importante rispetto alle versioni precedenti dove bisognava attivarlo esplicitamente.\n[mysqld] log_bin = /var/lib/mysql/mysql-bin server-id = 1 MySQL crea un nuovo file binlog in diverse circostanze:\nQuando il server si avvia o si riavvia Quando il file corrente raggiunge la dimensione definita da max_binlog_size (default: 1 GB) Quando esegui FLUSH BINARY LOGS Quando avviene una rotazione manuale Ogni file binlog ha un file indice associato (mysql-bin.index) che tiene traccia di tutti i file binlog attivi. Questo file è critico: se lo corrompi o lo modifichi a mano, MySQL non sa più quali binlog esistono.\nSHOW BINARY LOGS; +------------------+-----------+ | Log_name | File_size | +------------------+-----------+ | mysql-bin.000147 | 1073741824| | mysql-bin.000148 | 1073741824| | mysql-bin.000149 | 1073741824| | ... | | | mysql-bin.000318 | 524288000| +------------------+-----------+ 172 rows in set Centosettantadue file. Ognuno da circa un gigabyte. Il conto torna: 180 GB di binlog mai purgati.\nIl ruolo nella replica #In un\u0026rsquo;architettura master-slave, il binary log è il meccanismo di trasporto dei dati. Il flusso è questo:\nIl master scrive ogni transazione nel binlog Lo slave ha un thread (I/O thread) che si connette al master e legge i binlog Lo slave scrive ciò che riceve nel proprio relay log Un secondo thread (SQL thread) sullo slave esegue gli eventi dal relay log Questo significa che i binlog sul master devono restare disponibili finché tutti gli slave non li hanno letti. Se cancelli un binlog che lo slave non ha ancora consumato, la replica si rompe.\nPrima di toccare qualsiasi binlog su un master, il comando da eseguire è:\nSHOW REPLICA STATUS\\G -- oppure, su versioni più vecchie: SHOW SLAVE STATUS\\G Il campo che interessa è Relay_Master_Log_File (o Source_Log_File nelle versioni recenti): ti dice quale binlog lo slave sta leggendo in quel momento. Tutti i file precedenti a quello sono sicuri da eliminare.\nPoint-in-time recovery: l\u0026rsquo;altra ragione per cui i binlog esistono #Il secondo uso — spesso sottovalutato — è il point-in-time recovery. Lo scenario è questo: hai un backup fatto alle 3 di notte. Alle 14:30 qualcuno esegue un DROP TABLE sbagliato. Senza binlog, puoi fare restore del backup e perdi tutto ciò che è successo tra le 3:00 e le 14:30. Con i binlog, fai il restore e poi riapplichi i binlog fino alle 14:29.\n# Trovare l\u0026#39;evento del DROP TABLE mysqlbinlog --start-datetime=\u0026#34;2026-03-30 14:00:00\u0026#34; \\ --stop-datetime=\u0026#34;2026-03-30 15:00:00\u0026#34; \\ /var/lib/mysql/mysql-bin.000318 | grep -i \u0026#34;DROP\u0026#34; # Riapplicare i binlog fino al momento prima del disastro mysqlbinlog --stop-datetime=\u0026#34;2026-03-30 14:29:00\u0026#34; \\ /var/lib/mysql/mysql-bin.000310 \\ /var/lib/mysql/mysql-bin.000311 \\ ... \\ /var/lib/mysql/mysql-bin.000318 | mysql -u root -p In pratica, i binlog sono la tua assicurazione. Il backup è la base, i binlog coprono il delta. Cancellare i binlog senza un backup recente è come cancellare la polizza assicurativa il giorno prima di un temporale.\nPURGE BINARY LOGS: il modo corretto di fare pulizia #Torniamo al nostro server con il disco al 95%. La tentazione di fare un bel rm -f mysql-bin.* è forte. Ma è sbagliata, per due ragioni:\nMySQL non sa che hai cancellato i file — il file indice punta ancora a binlog che non esistono più Se c\u0026rsquo;è una replica attiva, rischi di rompere la sincronizzazione Il modo corretto è il comando PURGE:\n-- Eliminare tutti i binlog precedenti a un file specifico PURGE BINARY LOGS TO \u0026#39;mysql-bin.000300\u0026#39;; -- Oppure, eliminare tutti i binlog più vecchi di una certa data PURGE BINARY LOGS BEFORE \u0026#39;2026-03-01 00:00:00\u0026#39;; PURGE fa tre cose che rm non fa:\nAggiorna il file indice Verifica che i file non siano necessari alla replica (in teoria — ma controlla tu prima) Rimuove i file in modo ordinato Nel caso del nostro server, prima ho verificato che non ci fossero slave:\nSHOW REPLICAS; -- Empty set Nessuna replica. Poi ho verificato quale fosse il binlog corrente:\nSHOW MASTER STATUS; +------------------+----------+ | File | Position | +------------------+----------+ | mysql-bin.000318 | 52428800 | +------------------+----------+ Mantenendo gli ultimi 3 file per sicurezza:\nPURGE BINARY LOGS TO \u0026#39;mysql-bin.000316\u0026#39;; Risultato: 175 GB liberati in pochi secondi. Il disco è sceso dal 95% al 28%.\nConfigurare la retention automatica #Risolvere l\u0026rsquo;emergenza è un conto. Fare in modo che non ricapiti è un altro. MySQL offre due parametri per la gestione automatica della retention:\nexpire_logs_days (legacy) #[mysqld] expire_logs_days = 14 Elimina automaticamente i binlog più vecchi di 14 giorni. Semplice ma grossolano — la granularità è solo in giorni.\nbinlog_expire_logs_seconds (MySQL 8.0+) #[mysqld] binlog_expire_logs_seconds = 1209600 # 14 giorni in secondi Stessa logica, ma con granularità al secondo. Da MySQL 8.0, questo parametro ha la priorità su expire_logs_days. Se li imposti entrambi, vince binlog_expire_logs_seconds.\nLa domanda che mi fanno sempre è: \u0026ldquo;Quanti giorni di retention?\u0026rdquo;\nDipende. Ma ecco le mie regole pratiche:\nScenario Retention consigliata Server standalone, backup giornaliero 7 giorni Master con replica, backup giornaliero 7-14 giorni Master con replica lenta o in zone diverse 14-30 giorni Ambienti regolamentati (finanza, sanità) 30-90 giorni, con archivio Il principio è: la retention dei binlog deve coprire almeno il doppio dell\u0026rsquo;intervallo tra due backup. Se fai backup ogni notte, mantieni almeno 2-3 giorni di binlog. Se fai backup settimanali, almeno 14 giorni.\nNel caso del nostro server, non era stata impostata nessuna retention. Il default di MySQL 8.0 è 30 giorni — ma quel valore era stato sovrascritto a 0 (nessuna scadenza) in un my.cnf personalizzato da qualcuno che \u0026ldquo;voleva tenere tutto per sicurezza\u0026rdquo;. L\u0026rsquo;ironia: la sicurezza che voleva garantire stava per crashare il server riempiendo il disco.\nI tre formati del binlog: STATEMENT, ROW, MIXED #Non tutti i binlog sono uguali. MySQL supporta tre formati di registrazione, e la scelta ha implicazioni concrete.\nSTATEMENT #Registra l\u0026rsquo;istruzione SQL così com\u0026rsquo;è stata eseguita. Compatto, leggibile, ma problematico: funzioni come NOW(), UUID(), RAND() producono risultati diversi sul master e sullo slave. Le query con LIMIT senza ORDER BY possono produrre risultati non deterministici.\nSET binlog_format = \u0026#39;STATEMENT\u0026#39;; ROW #Registra il cambiamento a livello di riga — prima e dopo. Più pesante in termini di spazio, ma deterministico al 100%. Se aggiorni 10.000 righe, il binlog contiene 10.000 before/after image. Grande, ma sicuro.\nSET binlog_format = \u0026#39;ROW\u0026#39;; MIXED #MySQL decide caso per caso: usa STATEMENT quando è safe, passa automaticamente a ROW quando rileva operazioni non deterministiche.\nSET binlog_format = \u0026#39;MIXED\u0026#39;; Il mio consiglio: usa ROW. È il default da MySQL 5.7.7, è quello che Galera Cluster richiede, è quello che tutti i tool di replica moderni si aspettano. STATEMENT è un retaggio del passato, MIXED è un compromesso che aggiunge complessità senza un reale vantaggio.\nL\u0026rsquo;unico caso in cui ROW diventa un problema è quando fai operazioni massive — un UPDATE su milioni di righe genera un binlog enorme perché contiene il before e l\u0026rsquo;after di ogni riga. In quei casi, la soluzione non è cambiare formato, ma spezzare l\u0026rsquo;operazione in batch:\n-- Invece di questo (genera binlog gigantesco): UPDATE orders SET status = \u0026#39;archived\u0026#39; WHERE order_date \u0026lt; \u0026#39;2025-01-01\u0026#39;; -- Meglio così (batch da 10.000): UPDATE orders SET status = \u0026#39;archived\u0026#39; WHERE order_date \u0026lt; \u0026#39;2025-01-01\u0026#39; AND status != \u0026#39;archived\u0026#39; LIMIT 10000; -- Ripetere fino a 0 rows affected mysqlbinlog: leggere i binlog quando serve #Il tool da riga di comando `mysqlbinlog` è l\u0026rsquo;unico modo per ispezionare il contenuto dei file binlog. Serve in due scenari: debug di problemi di replica e point-in-time recovery.\n# Leggere un binlog in formato leggibile mysqlbinlog /var/lib/mysql/mysql-bin.000318 # Filtrare per intervallo temporale mysqlbinlog --start-datetime=\u0026#34;2026-03-30 10:00:00\u0026#34; \\ --stop-datetime=\u0026#34;2026-03-30 11:00:00\u0026#34; \\ /var/lib/mysql/mysql-bin.000318 # Filtrare per database specifico mysqlbinlog --database=gestionale /var/lib/mysql/mysql-bin.000318 # Se il formato è ROW, decodificare in SQL leggibile mysqlbinlog --verbose /var/lib/mysql/mysql-bin.000318 Con il formato ROW, senza --verbose vedi solo blob binari. Con --verbose ottieni le righe in formato pseudo-SQL commentato — non bellissimo, ma leggibile.\nIl principio: gestire i binlog, non disabilitarli #Ogni tanto qualcuno suggerisce di risolvere il problema \u0026ldquo;alla radice\u0026rdquo; disabilitando i binlog:\n# NON FARE QUESTO in produzione skip-log-bin Sì, risolve il problema del disco. Ma elimina:\nLa possibilità di configurare una replica in futuro Il point-in-time recovery La capacità di analizzare cosa è successo nel database dopo un incidente La compatibilità con strumenti di CDC (Change Data Capture) come Debezium I binlog non sono un problema. I binlog non gestiti sono un problema. La differenza è un parametro di configurazione e un check settimanale. Sul server che ho sistemato, la configurazione finale è stata:\n[mysqld] log_bin = /var/lib/mysql/mysql-bin server-id = 1 binlog_format = ROW binlog_expire_logs_seconds = 604800 # 7 giorni max_binlog_size = 512M Un max_binlog_size di 512 MB invece del default di 1 GB — file più piccoli sono più facili da gestire, trasferire e purgare. La retention a 7 giorni, con backup giornaliero, garantisce copertura PITR completa con occupazione disco prevedibile.\nCheck-up post intervento #Prima di chiudere il ticket, ho aggiunto un paio di query al sistema di monitoraggio del cliente:\n-- Spazio occupato dai binlog SELECT COUNT(*) AS num_files, ROUND(SUM(file_size) / 1024 / 1024 / 1024, 2) AS total_gb FROM information_schema.BINARY_LOGS; -- MySQL 8.0+ / Performance Schema -- Oppure, per tutte le versioni: SHOW BINARY LOGS; -- e sommare manualmente o via script # Alert se i binlog superano i 20 GB #!/bin/bash BINLOG_SIZE=$(mysql -u monitor -p\u0026#39;pwd\u0026#39; -Bse \\ \u0026#34;SELECT ROUND(SUM(file_size)/1024/1024/1024,2) FROM performance_schema.binary_log_status\u0026#34; 2\u0026gt;/dev/null) # Fallback per versioni senza performance_schema.binary_log_status if [ -z \u0026#34;$BINLOG_SIZE\u0026#34; ]; then BINLOG_SIZE=$(du -sh /var/lib/mysql/mysql-bin.* 2\u0026gt;/dev/null | \\ awk \u0026#39;{sum+=$1} END {printf \u0026#34;%.2f\u0026#34;, sum/1024}\u0026#39;) fi if (( $(echo \u0026#34;$BINLOG_SIZE \u0026gt; 20\u0026#34; | bc -l) )); then echo \u0026#34;WARNING: binlog size ${BINLOG_SIZE} GB\u0026#34; fi Tre settimane dopo l\u0026rsquo;intervento, i binlog occupavano 8 GB — esattamente nella finestra prevista. Il disco non è più andato sopra il 45%.\nIl binlog è come l\u0026rsquo;olio del motore: non ci pensi mai finché non si accende la spia. La differenza è che il motore ti avvisa. MySQL no — continua a scrivere binlog finché il filesystem risponde. Quando smette di rispondere, è troppo tardi per chiedersi perché non avevi impostato la retention.\nGlossario #Binary log — Registro binario sequenziale di MySQL che traccia tutte le modifiche ai dati (INSERT, UPDATE, DELETE, DDL), usato per la replica e il point-in-time recovery. Da MySQL 8.0 è abilitato di default.\nPITR — Point-in-Time Recovery: tecnica di ripristino che combina un backup completo con i binary log per riportare il database a un qualsiasi momento nel tempo, non solo all\u0026rsquo;ora del backup.\nRelay log — File di log intermedio sullo slave MySQL che riceve gli eventi dal binary log del master prima che vengano eseguiti localmente dal thread SQL.\nCDC — Change Data Capture: tecnica per intercettare le modifiche ai dati in tempo reale leggendo i log delle transazioni. Strumenti come Debezium leggono i binary log di MySQL per propagare i cambiamenti verso sistemi esterni.\nmysqlbinlog — Utility da riga di comando di MySQL per leggere, filtrare e riapplicare il contenuto dei file binary log. Indispensabile per il point-in-time recovery e il debug della replica.\n","date":"31 marzo 2026","permalink":"https://ivanluminaria.com/it/posts/mysql/binary-log-mysql/","section":"Database Strategy","summary":"\u003cp\u003eIl messaggio nel canale Slack del team infrastruttura era di quelli che fanno alzare la testa dallo schermo: \u0026ldquo;Disco al 95% sul db di produzione. Chi può guardare?\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eIl server era un MySQL 8.0 su Rocky Linux, un gestionale usato da un centinaio di utenti. Il database in sé occupava circa 40 GB — niente di straordinario. Ma nella directory dei dati c\u0026rsquo;erano 180 GB di binary log. Sei mesi di binlog che nessuno aveva mai pensato di gestire.\u003c/p\u003e","title":"Binary log in MySQL: cosa sono, come gestirli e quando puoi cancellarli"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/binlog/","section":"Tags","summary":"","title":"Binlog"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/disk-space/","section":"Tags","summary":"","title":"Disk-Space"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/recovery/","section":"Tags","summary":"","title":"Recovery"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/replication/","section":"Tags","summary":"","title":"Replication"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/autovacuum/","section":"Tags","summary":"","title":"Autovacuum"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/bloat/","section":"Tags","summary":"","title":"Bloat"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/mvcc/","section":"Tags","summary":"","title":"Mvcc"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/categories/postgresql/","section":"Categories","summary":"","title":"Postgresql"},{"content":"PostgreSQL non è solo un database open source.\nÈ il risultato di quasi quarant’anni di evoluzione accademica e industriale.\nNato nel 1986 all’Università di Berkeley come evoluzione di Ingres, il progetto POSTGRES introduceva concetti che all’epoca erano avanguardia: estendibilità, tipi di dato personalizzati, regole e un modello relazionale avanzato.\nNel 1996 arriva il supporto SQL e il nome cambia in PostgreSQL.\nIl mondo però ha continuato a chiamarlo semplicemente “Postgres”.\nE va bene così.\nIn questa sezione esploro PostgreSQL dal punto di vista architetturale e operativo: progettazione, performance, sicurezza e scelte tecniche applicabili in ambienti reali.\nPerché usare PostgreSQL non significa solo scegliere un database open source.\nSignifica scegliere un motore progettato per essere esteso, analizzato e compreso.\n","date":null,"permalink":"https://ivanluminaria.com/it/posts/postgresql/","section":"Database Strategy","summary":"\u003cp\u003ePostgreSQL non è solo un database open source.\u003cbr\u003e\nÈ il risultato di quasi quarant’anni di evoluzione accademica e industriale.\u003cbr\u003e\u003c/p\u003e\n\u003cp\u003eNato nel 1986 all’Università di Berkeley come evoluzione di Ingres, il progetto POSTGRES introduceva concetti che all’epoca erano avanguardia: estendibilità, tipi di dato personalizzati, regole e un modello relazionale avanzato.\u003cbr\u003e\u003c/p\u003e\n\u003cp\u003eNel 1996 arriva il supporto SQL e il nome cambia in PostgreSQL.\u003cbr\u003e\nIl mondo però ha continuato a chiamarlo semplicemente “Postgres”.\u003cbr\u003e\nE va bene così.\u003cbr\u003e\u003c/p\u003e","title":"PostgreSQL"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/vacuum/","section":"Tags","summary":"","title":"Vacuum"},{"content":"Un paio d\u0026rsquo;anni fa mi chiedono di guardare un PostgreSQL in produzione che \u0026ldquo;rallenta ogni settimana\u0026rdquo;. Sempre lo stesso pattern: lunedì va bene, venerdì è un disastro. Il weekend qualcuno riavvia il servizio e si ricomincia.\nDatabase da circa 200 GB. Tabelle principali che occupavano quasi il triplo dello spazio effettivo dei dati. Query che andavano in sequential scan su tabelle dove non avrebbero dovuto. Tempi di risposta che salivano di giorno in giorno.\nL\u0026rsquo;autovacuum era attivo. Nessuno l\u0026rsquo;aveva disabilitato. Ma nessuno l\u0026rsquo;aveva nemmeno configurato.\n🧠 MVCC: perché PostgreSQL genera \u0026ldquo;spazzatura\u0026rdquo; #Per capire il problema serve un passo indietro. PostgreSQL usa MVCC — Multi-Version Concurrency Control. Ogni volta che fai un UPDATE, il database non sovrascrive la riga originale. Crea una nuova versione e segna la vecchia come \u0026ldquo;morta\u0026rdquo;.\nStesso discorso per le DELETE: la riga non viene cancellata fisicamente. Viene marcata come non più visibile alle nuove transazioni.\nQueste righe morte si chiamano dead tuples. E restano lì, dentro le pagine dati, occupando spazio su disco e rallentando le scansioni.\nÈ il prezzo che PostgreSQL paga per avere isolamento transazionale senza lock esclusivi sulle letture. Un prezzo ragionevole — a patto che qualcuno passi a pulire.\n🔧 VACUUM: cosa fa davvero #Il comando VACUUM fa una cosa semplice: recupera lo spazio occupato dai dead tuples e lo rende riutilizzabile per nuovi inserimenti.\nNon restituisce spazio al sistema operativo. Non riorganizza la tabella. Non compatta nulla. Segna le pagine come riscrivibili.\nVACUUM reporting.transactions; Questo basta nella maggior parte dei casi. Il VACUUM è leggero, non blocca le scritture, e può girare in parallelo con le query normali.\nE VACUUM FULL? #VACUUM FULL è un\u0026rsquo;altra bestia. Riscrive fisicamente l\u0026rsquo;intera tabella, eliminando tutto lo spazio morto. Restituisce spazio al filesystem.\nMa ha un costo brutale: prende un lock esclusivo sulla tabella per tutta la durata dell\u0026rsquo;operazione. Nessuno legge, nessuno scrive. Su tabelle grandi parliamo di minuti o ore.\nVACUUM FULL reporting.transactions; In produzione, VACUUM FULL va usato rarissimamente. In emergenza. E sempre fuori orario.\n⚙️ Autovacuum: il custode silenzioso #PostgreSQL ha un daemon che fa il VACUUM in automatico: l\u0026rsquo;autovacuum.\nParte quando una tabella accumula abbastanza dead tuples. Il threshold è calcolato così:\nvacuum threshold = autovacuum_vacuum_threshold + autovacuum_vacuum_scale_factor × n_live_tup I default:\nautovacuum_vacuum_threshold: 50 dead tuples autovacuum_vacuum_scale_factor: 0.2 (20%) Tradotto: su una tabella con 10 milioni di righe, l\u0026rsquo;autovacuum parte quando i dead tuples superano 2.000.050. Due milioni di righe morte prima che qualcuno faccia pulizia.\nPer una tabella con 500.000 update al giorno, significa che l\u0026rsquo;autovacuum si attiva forse ogni 4 giorni. Nel frattempo il bloat cresce, le scansioni rallentano, gli indici si gonfiano.\nEcco perché lunedì andava tutto bene e venerdì era un disastro.\n📊 Diagnostica: leggere pg_stat_user_tables #La prima cosa da fare quando sospetti un problema di vacuum è interrogare pg_stat_user_tables:\nSELECT schemaname, relname, n_live_tup, n_dead_tup, round(100.0 * n_dead_tup / NULLIF(n_live_tup + n_dead_tup, 0), 1) AS dead_pct, last_vacuum, last_autovacuum, autovacuum_count, vacuum_count FROM pg_stat_user_tables WHERE n_dead_tup \u0026gt; 10000 ORDER BY n_dead_tup DESC; Nel caso del mio cliente, la situazione era questa:\nrelname | n_live_tup | n_dead_tup | dead_pct | last_autovacuum -------------------+------------+------------+----------+------------------ transactions | 12.400.000 | 3.800.000 | 23.5% | 3 days ago order_lines | 8.200.000 | 2.100.000 | 20.4% | 4 days ago inventory_moves | 5.600.000 | 1.900.000 | 25.3% | 5 days ago Quasi un quarto delle righe erano morte. L\u0026rsquo;autovacuum girava, ma troppo raramente per tenere il passo.\n🎯 Tuning: adattare l\u0026rsquo;autovacuum alla realtà #Il trucco non è disabilitare l\u0026rsquo;autovacuum. Mai. Il trucco è configurarlo per le tabelle che ne hanno bisogno.\nPostgreSQL permette di impostare parametri di autovacuum per singola tabella:\nALTER TABLE reporting.transactions SET ( autovacuum_vacuum_scale_factor = 0.01, autovacuum_vacuum_threshold = 1000 ); Con questo setting, l\u0026rsquo;autovacuum parte dopo 1.000 + 1% delle righe vive di dead tuples. Su 12 milioni di righe, si attiva a ~121.000 dead tuples invece che a 2 milioni.\ncost_delay: non strangolare il vacuum #Un altro parametro critico è autovacuum_vacuum_cost_delay. Controlla quanto il vacuum \u0026ldquo;rallenta sé stesso\u0026rdquo; per non sovraccaricare l\u0026rsquo;I/O.\nIl default è 2 millisecondi. Su server moderni con SSD, è troppo conservativo. Ridurlo a 0 o 1 ms permette al vacuum di finire prima:\nALTER TABLE reporting.transactions SET ( autovacuum_vacuum_cost_delay = 0 ); max_workers #Il default è 3 worker di autovacuum. Se hai decine di tabelle ad alto traffico, 3 worker non bastano. Valuta di portarli a 5–6, monitorando l\u0026rsquo;impatto su CPU e I/O:\n-- in postgresql.conf autovacuum_max_workers = 5 📏 Misurare il bloat #Come fai a sapere quanto spazio stanno sprecando le tue tabelle?\nLa query classica usa pgstattuple:\nCREATE EXTENSION IF NOT EXISTS pgstattuple; SELECT pg_size_pretty(pg_total_relation_size(\u0026#39;reporting.transactions\u0026#39;)) AS total_size, pg_size_pretty(pg_total_relation_size(\u0026#39;reporting.transactions\u0026#39;) - pg_relation_size(\u0026#39;reporting.transactions\u0026#39;)) AS index_size, * FROM pgstattuple(\u0026#39;reporting.transactions\u0026#39;); I campi chiave: dead_tuple_percent e free_space. Se il dead_tuple supera il 20–30%, la tabella ha un problema serio.\nUn\u0026rsquo;alternativa meno precisa ma più leggera è stimare il bloat ratio confrontando pg_class.relpages con le righe stimate — ci sono query consolidate nella community per questo (la classica \u0026ldquo;bloat estimation query\u0026rdquo; di PostgreSQL Experts).\n🛠️ Quando VACUUM non basta: pg_repack #Se il bloat è ormai fuori controllo — tabelle al 50–70% di spazio morto — il VACUUM normale non recupera tutto. Libera i dead tuples, ma lo spazio frammentato resta.\nVACUUM FULL funziona, ma blocca tutto.\nL\u0026rsquo;alternativa in produzione è pg_repack: ricostruisce la tabella online, senza lock esclusivi prolungati.\npg_repack -d mydb -t reporting.transactions Non è una soluzione da usare ogni settimana. È la cura d\u0026rsquo;urto per quando la situazione è già degenerata. La vera soluzione è non arrivarci, con un autovacuum ben configurato.\n💬 Il principio #Disabilitare l\u0026rsquo;autovacuum è la peggior cosa che puoi fare a un PostgreSQL in produzione. L\u0026rsquo;ho visto fare \u0026ldquo;perché rallenta le query durante il giorno\u0026rdquo;. Certo, perché nel frattempo il bloat ti mangia il database da dentro.\nL\u0026rsquo;autovacuum con i default di PostgreSQL è pensato per un database generico. Nessun database in produzione è generico. Ogni tabella ha il suo pattern di write, il suo volume, il suo ritmo.\nTre cose da portarsi via:\nControlla pg_stat_user_tables regolarmente. Se n_dead_tup cresce più velocemente di quanto l\u0026rsquo;autovacuum riesca a pulire, hai un problema.\nConfigura scale_factor e threshold per le tabelle ad alto traffico. Non esiste una configurazione universale.\nNon aspettare che il bloat arrivi al 50% per intervenire. A quel punto le opzioni sono poche e tutte dolorose.\nI database non si mantengono da soli. Nemmeno quelli che hanno un daemon che ci prova.\nGlossario #VACUUM — Comando PostgreSQL che recupera lo spazio occupato dai dead tuples, rendendolo riutilizzabile per nuovi inserimenti senza restituirlo al sistema operativo.\nMVCC — Multi-Version Concurrency Control — modello di concorrenza di PostgreSQL che mantiene più versioni delle righe per garantire isolamento transazionale senza lock esclusivi sulle letture.\nDead Tuple — Riga obsoleta in una tabella PostgreSQL, marcata come non più visibile dopo un UPDATE o DELETE ma non ancora rimossa fisicamente dal disco.\nAutovacuum — Daemon PostgreSQL che esegue automaticamente VACUUM e ANALYZE sulle tabelle quando il numero di dead tuples supera una soglia configurabile.\nBloat — Spazio morto accumulato in una tabella o indice PostgreSQL a causa di dead tuples non rimossi, che gonfia la dimensione su disco e degrada le performance.\n","date":"24 marzo 2026","permalink":"https://ivanluminaria.com/it/posts/postgresql/vacuum-autovacuum-postgresql/","section":"Database Strategy","summary":"\u003cp\u003eUn paio d\u0026rsquo;anni fa mi chiedono di guardare un PostgreSQL in produzione che\n\u0026ldquo;rallenta ogni settimana\u0026rdquo;. Sempre lo stesso pattern: lunedì va bene,\nvenerdì è un disastro. Il weekend qualcuno riavvia il servizio e si\nricomincia.\u003c/p\u003e\n\u003cp\u003eDatabase da circa 200 GB. Tabelle principali che occupavano quasi il\ntriplo dello spazio effettivo dei dati. Query che andavano in sequential\nscan su tabelle dove non avrebbero dovuto. Tempi di risposta che\nsalivano di giorno in giorno.\u003c/p\u003e","title":"VACUUM e autovacuum: perché PostgreSQL ha bisogno che qualcuno pulisca"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/ai/","section":"Tags","summary":"","title":"Ai"},{"content":"Qualche mese fa, durante una riunione con un cliente del settore bancario, il CTO ha detto una frase che mi è rimasta in testa.\n\u0026ldquo;Ci serve qualcuno che gestisca l\u0026rsquo;AI. Non uno che la usi — uno che la governi.\u0026rdquo;\nHo annuito senza parlare. Perché quella frase, in sette secondi, descriveva un ruolo che il mercato sta cercando senza sapere ancora come chiamarlo.\n🧩 Il malinteso fondamentale #C\u0026rsquo;è una confusione diffusa, e la vedo in ogni progetto dove l\u0026rsquo;AI entra in gioco.\nLa confusione è questa: pensare che \u0026ldquo;adottare l\u0026rsquo;AI\u0026rdquo; significhi integrare un modello, collegare un\u0026rsquo;API, far generare del testo o del codice a un assistente.\nNo. Quello è l\u0026rsquo;aspetto tecnico. L\u0026rsquo;aspetto operativo. È il lavoro di un data scientist o di un ingegnere ML. Lavoro importante, sia chiaro. Ma non è il lavoro di chi governa.\nGovernare l\u0026rsquo;AI in un progetto significa rispondere a domande che nessun modello può rispondere al tuo posto:\nDove l\u0026rsquo;AI genera valore reale e dove genera solo entusiasmo? Quanto costa mantenerla, non solo implementarla? Cosa succede quando il modello sbaglia — e chi ne risponde? Come si integra con le architetture che già esistono, senza compromettere stabilità e sicurezza? Come si garantisce coerenza tra governance del dato, compliance e automazione? Se non hai risposte a queste domande, non stai governando l\u0026rsquo;AI. La stai subendo.\n🏗️ Non è un ruolo nuovo. È un ruolo che non aveva ancora un nome #Quando ci penso, mi accorgo che faccio questo lavoro da molto prima che qualcuno inventasse l\u0026rsquo;etichetta \u0026ldquo;AI Manager\u0026rdquo;.\nTrent\u0026rsquo;anni di architetture dati. Sistemi mission-critical in Telco, Banking, Assicurazioni, Pubblica Amministrazione. Ambienti dove il dato non è un asset da monetizzare — è un\u0026rsquo;infrastruttura da proteggere.\nIn quei contesti ho sempre fatto la stessa cosa: collegare la strategia alla realtà tecnica. Tradurre le esigenze del business in soluzioni che funzionano davvero, non sulla slide ma in produzione. Mediare tra chi vuole tutto subito e chi sa che certe cose richiedono tempo e architettura.\nL\u0026rsquo;AI non ha cambiato questo schema. L\u0026rsquo;ha reso più visibile.\nPerché l\u0026rsquo;AI, a differenza di un database o di un ETL, è un argomento che eccita i board e spaventa i tecnici. Tutti ne vogliono un pezzo, pochi sanno dove metterlo. E il ruolo di chi sta in mezzo — tra l\u0026rsquo;entusiasmo del management e la prudenza dell\u0026rsquo;infrastruttura — diventa cruciale.\n📍 Dove l\u0026rsquo;AI genera valore reale (e dove no) #Ho imparato una cosa negli ultimi tre anni, lavorando con l\u0026rsquo;AI in contesti progettuali concreti: il valore dell\u0026rsquo;AI non sta quasi mai dove la gente pensa.\nNon sta nella generazione automatica di codice. Non sta nel chatbot che risponde ai clienti. Non sta nel report che si scrive da solo.\nIl valore reale sta in tre posti:\n1. Accelerazione dell\u0026rsquo;analisi\nL\u0026rsquo;AI è devastante quando deve analizzare contesto. Leggere migliaia di righe di codice, correlare log, individuare pattern. Quello che a un senior costa due ore, l\u0026rsquo;AI lo fa in secondi. Non meglio — più in fretta. E la velocità, in un progetto con deadline, è denaro.\n2. Riduzione del rumore decisionale\nIn ogni progetto complesso c\u0026rsquo;è un momento in cui le informazioni sono troppe e il team non sa più cosa è urgente e cosa è importante. L\u0026rsquo;AI può fare triage. Può classificare, prioritizzare, evidenziare anomalie. Non decide al posto tuo — ti presenta i dati in modo che la decisione diventi più chiara.\n3. Documentazione e knowledge transfer\nNessuno documenta volentieri. Nessuno. L\u0026rsquo;AI può generare documentazione a partire dal codice, dai commit, dalle issue. Non perfetta, ma sufficiente per non perdere conoscenza quando qualcuno lascia il progetto. E chi ha gestito progetti sa quanto questo costi.\nTutto il resto — i demo che luccicano, le presentazioni con le percentuali in grassetto, i vendor che promettono ROI a tre cifre — è rumore. L\u0026rsquo;AI Manager è chi separa il segnale dal rumore.\n⚖️ Il triangolo che il PM deve governare #In ogni progetto dove l\u0026rsquo;AI entra in un ambiente regolamentato, c\u0026rsquo;è un triangolo che torna sempre:\nGovernance del dato — Compliance — Automazione.\nPuoi avere l\u0026rsquo;automazione più efficiente del mondo, ma se viola le policy di data governance, è un rischio. Puoi avere una governance impeccabile, ma se blocca ogni forma di automazione, il progetto non avanza. Puoi essere perfettamente compliant, ma se non sai quali dati stai usando per addestrare o interrogare il modello, la compliance è solo sulla carta.\nL\u0026rsquo;AI Manager deve tenere in equilibrio questi tre vertici. Continuamente. Non una volta all\u0026rsquo;inizio del progetto — ogni settimana.\nHo visto progetti dove l\u0026rsquo;AI veniva integrata senza che nessuno avesse verificato la provenienza dei dati di training. In ambito bancario. Con dati soggetti a GDPR. Il DPO l\u0026rsquo;ha scoperto tre mesi dopo.\nNon è incompetenza. È assenza di governance. È assenza di qualcuno che faccia la domanda giusta al momento giusto.\n🔬 Integrare, non sostituire #Una cosa che ripeto in ogni kickoff meeting: l\u0026rsquo;AI si integra nelle architetture esistenti. Non le sostituisce.\nSembra banale, eppure la tentazione è sempre la stessa: il vendor che propone di \u0026ldquo;ripensare l\u0026rsquo;infrastruttura in chiave AI\u0026rdquo;, il consulente che vuole una greenfield architecture, il manager che ha visto una demo e adesso vuole tutto nuovo.\nNo.\nLe architetture mission-critical non si buttano via perché è arrivata una tecnologia nuova. Si evolvono. Si estendono. Si proteggono.\nL\u0026rsquo;AI Manager è chi dice \u0026ldquo;questo modello si innesta qui, con queste precauzioni, con questo piano di fallback\u0026rdquo;. Non chi dice \u0026ldquo;buttiamo tutto e rifacciamo con l\u0026rsquo;AI\u0026rdquo;.\nIn trent\u0026rsquo;anni di sistemi, ho visto almeno cinque tecnologie \u0026ldquo;rivoluzionarie\u0026rdquo; che avrebbero dovuto cambiare tutto. Client-server. Internet. Cloud. Big Data. Adesso AI. Nessuna ha cambiato tutto. Ognuna ha cambiato qualcosa. E chi ha governato bene il cambiamento è chi l\u0026rsquo;ha integrato con intelligenza — non con entusiasmo.\n🎯 Perché l\u0026rsquo;AI non è magia #C\u0026rsquo;è una frase che uso spesso, e non mi stanco di ripeterla.\nL\u0026rsquo;AI non è magia. È architettura applicata all\u0026rsquo;intelligenza.\nUn modello è un componente. Come un database, come un message broker, come un load balancer. Ha bisogno di input puliti, di monitoring, di manutenzione, di governance. Ha bisogno di qualcuno che capisca cosa fa, cosa può fare, e soprattutto cosa non può fare.\nIl Project Manager che ignora questi aspetti e delega tutto al team tecnico sta commettendo lo stesso errore di chi delegava la sicurezza al sistemista e poi si stupiva del data breach.\nL\u0026rsquo;AI è una responsabilità architetturale. E come tutte le responsabilità architetturali, va governata dall\u0026rsquo;alto. Non dal basso.\n💬 A chi sta decidendo se l\u0026rsquo;AI \u0026ldquo;serve\u0026rdquo; nel proprio progetto #Se stai valutando di introdurre l\u0026rsquo;AI in un progetto — non in un esperimento, in un progetto vero, con deadline, budget e stakeholder — ti do un consiglio che vale più di qualsiasi tool.\nNon partire dalla tecnologia. Parti dal problema.\nQual è il collo di bottiglia? Dove il team perde più tempo? Dove le decisioni sono più lente del necessario? Dove si perde conoscenza?\nSe la risposta a una di queste domande ha a che fare con l\u0026rsquo;analisi di grandi quantità di dati, con la classificazione di informazioni, con l\u0026rsquo;accelerazione di processi ripetitivi — allora l\u0026rsquo;AI può aiutarti. Ma solo se qualcuno la governa.\nE governarla non significa controllarla. Significa capirla abbastanza da sapere quando fidarsi e quando no.\nQuello è il lavoro dell\u0026rsquo;AI Manager. E, che lo si chiami così o no, è un ruolo che ogni progetto serio avrà bisogno di avere.\nGlossario #AI Manager — Ruolo professionale che governa l\u0026rsquo;impatto dell\u0026rsquo;intelligenza artificiale su architetture, processi e persone, separando il valore reale dal rumore.\nData Governance — Insieme di politiche, processi e standard che garantiscono la qualità, la sicurezza e la conformità dei dati all\u0026rsquo;interno di un\u0026rsquo;organizzazione.\nKnowledge Transfer — Processo di trasferimento della conoscenza tra persone, team o sistemi, critico nei progetti IT dove la perdita di know-how può compromettere la continuità operativa.\nROI — Return on Investment — rapporto tra il beneficio ottenuto e il costo sostenuto per un investimento.\nCompliance — Conformità alle normative, regolamenti e standard applicabili — nel contesto AI include GDPR, regolamenti di settore e policy interne sull\u0026rsquo;uso dei dati.\n","date":"17 marzo 2026","permalink":"https://ivanluminaria.com/it/posts/project-management/ai-manager-project-management/","section":"Database Strategy","summary":"\u003cp\u003eQualche mese fa, durante una riunione con un cliente del settore bancario, il CTO ha detto una frase che mi è rimasta in testa.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u0026ldquo;Ci serve qualcuno che gestisca l\u0026rsquo;AI. Non uno che la usi — uno che la governi.\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eHo annuito senza parlare. Perché quella frase, in sette secondi, descriveva un ruolo che il mercato sta cercando senza sapere ancora come chiamarlo.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"-il-malinteso-fondamentale\" class=\"relative group\"\u003e🧩 Il malinteso fondamentale \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-il-malinteso-fondamentale\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eC\u0026rsquo;è una confusione diffusa, e la vedo in ogni progetto dove l\u0026rsquo;AI entra in gioco.\u003c/p\u003e","title":"AI Manager e Project Management: quando l'intelligenza artificiale entra nei progetti"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/ai-manager/","section":"Tags","summary":"","title":"Ai-Manager"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/governance/","section":"Tags","summary":"","title":"Governance"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/categories/project-management/","section":"Categories","summary":"","title":"Project Management"},{"content":"Ho visto project manager far piangere sviluppatori senior in riunione. Ho visto team brillanti distrutti da PM che confondevano l\u0026rsquo;autorità con l\u0026rsquo;autoritarismo. Ho visto software consegnati \u0026ldquo;in tempo\u0026rdquo; che non funzionavano, e progetti da milioni di euro finiti nel nulla.\nE ho visto l\u0026rsquo;esatto contrario: team piccoli, autonomi, rispettati — che costruivano sistemi solidi in una frazione del tempo e del budget.\nLa differenza non è mai stata la tecnologia. È sempre stata il metodo.\nDopo trent\u0026rsquo;anni in questo mestiere, una cosa l\u0026rsquo;ho capita: le persone non danno il meglio quando hanno paura. Danno il meglio quando hanno fiducia.\nFiducia nel team. Fiducia nel processo. Fiducia nel fatto che se sbagliano non verranno punite — verranno aiutate.\nIl project manager che funziona non è quello che controlla, terrorizza e conta le ore. È quello che:\ndefinisce obiettivi chiari e lascia al team la libertà di raggiungerli costruisce competenze profonde e le protegge dal turnover fa team building ogni giorno, non una volta l\u0026rsquo;anno al go-kart misura i risultati, non le ore in ufficio usa lo smart working come vantaggio competitivo, non come concessione quando qualcosa va storto, si mette davanti al team, non dietro 📊 Come lavoro io #Il mio approccio è Scrum — ma Scrum fatto sul serio, non la liturgia dei post-it.\nLo Scrum che funziona si basa su un patto: trasparenza radicale, responsabilità condivisa e autonomia nel \u0026ldquo;come\u0026rdquo;. Il PM definisce il cosa e il perché. Il team decide il come. Perché chi scrive il codice sa meglio di chiunque altro come scriverlo.\nE questo patto funziona ancora meglio nello smart working. La daily standup? 15 minuti in call. La sprint review? Screen sharing con il cliente, che vede il software — non le slide. La retrospettiva? Un\u0026rsquo;ora in cui il team dice la verità, perché non ha il PM a due metri che lo fissa.\nMisuro poche cose, ma le misuro bene:\nMetrica Cosa dice Velocity Quanto il team consegna per sprint Lead time Quanto passa da richiesta a rilascio Bug escape rate Quanti difetti sfuggono in produzione Sprint goal success % di obiettivi di sprint raggiunti Team happiness Come si sente il team — la metrica più importante L\u0026rsquo;ultima — team happiness — è quella che i PM tradizionali non misurano mai. Un team felice non è un team che si diverte. È un team che si sente rispettato, ascoltato e valorizzato. E un team così produce di più. Non perché lavora più ore. Perché lavora meglio.\n📚 Di cosa parlo qui #Storie vere, numeri concreti e lezioni apprese. Niente teoria da manuale. Solo quello che ho visto funzionare — e quello che ho visto fallire.\nSi parla di intelligenza artificiale applicata al workflow, di consulenza IT e dei suoi costi nascosti, di smart working come vantaggio competitivo. Ogni articolo nasce da un\u0026rsquo;esperienza reale — la mia.\nNon servono rivoluzioni. Servono scelte precise, implementate con metodo.\nE la capacità di dire \u0026ldquo;no\u0026rdquo; a chi ti vende complessità quando la soluzione è semplice.\n","date":null,"permalink":"https://ivanluminaria.com/it/posts/project-management/","section":"Database Strategy","summary":"\u003cp\u003eHo visto project manager far piangere sviluppatori senior in riunione. Ho visto team brillanti distrutti da PM che confondevano l\u0026rsquo;autorità con l\u0026rsquo;autoritarismo. Ho visto software consegnati \u0026ldquo;in tempo\u0026rdquo; che non funzionavano, e progetti da milioni di euro finiti nel nulla.\u003c/p\u003e\n\u003cp\u003eE ho visto l\u0026rsquo;esatto contrario: team piccoli, autonomi, rispettati — che costruivano sistemi solidi in una frazione del tempo e del budget.\u003c/p\u003e\n\u003cp\u003eLa differenza non è mai stata la tecnologia. È sempre stata \u003cstrong\u003eil metodo\u003c/strong\u003e.\u003c/p\u003e","title":"Project Management"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/project-management/","section":"Tags","summary":"","title":"Project-Management"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/strategy/","section":"Tags","summary":"","title":"Strategy"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/consulting/","section":"Tags","summary":"","title":"Consulting"},{"content":"Un data warehouse non è un database con le tabelle più grandi.\nÈ un modo diverso di pensare ai dati — orientato all\u0026rsquo;analisi, alla storia, alle decisioni.\nLa differenza tra un DWH che funziona e uno che diventa un problema sta quasi sempre nel modello. Tabelle dei fatti con la granularità sbagliata, dimensioni mal progettate, gerarchie che non reggono le query di aggregazione. Problemi che non si vedono in fase di sviluppo, ma esplodono quando il business chiede report che il modello non può supportare.\nIn questa sezione racconto casi reali di progettazione e ristrutturazione di data warehouse: modellazione dimensionale, gerarchie bilanciate, slowly changing dimensions, strategie di caricamento. Non teoria da libro di Kimball, ma soluzioni applicate in produzione su sistemi che servono decisioni aziendali vere.\nPerché un data warehouse non si costruisce per contenere dati.\nSi costruisce per rispondere a domande.\n","date":null,"permalink":"https://ivanluminaria.com/it/posts/data-warehouse/","section":"Database Strategy","summary":"\u003cp\u003eUn data warehouse non è un database con le tabelle più grandi.\u003cbr\u003e\nÈ un modo diverso di pensare ai dati — orientato all\u0026rsquo;analisi, alla storia, alle decisioni.\u003cbr\u003e\u003c/p\u003e\n\u003cp\u003eLa differenza tra un DWH che funziona e uno che diventa un problema sta quasi sempre nel modello. Tabelle dei fatti con la granularità sbagliata, dimensioni mal progettate, gerarchie che non reggono le query di aggregazione. Problemi che non si vedono in fase di sviluppo, ma esplodono quando il business chiede report che il modello non può supportare.\u003cbr\u003e\u003c/p\u003e","title":"Data Warehouse"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/european-union/","section":"Tags","summary":"","title":"European-Union"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/freelance/","section":"Tags","summary":"","title":"Freelance"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/italy/","section":"Tags","summary":"","title":"Italy"},{"content":"Oracle è il database che mi ha formato professionalmente.\nCi lavoro dal 1996, e in quasi trent\u0026rsquo;anni ho visto passare versioni, paradigmi e mode — ma il cuore del motore è rimasto lo stesso: solido, complesso, spietato con chi non lo conosce a fondo.\nHo gestito istanze da poche centinaia di utenti e data warehouse da miliardi di righe. Ho configurato Data Guard quando ancora si chiamava standby database, ho scritto PL/SQL quando il debugging significava DBMS_OUTPUT e pazienza, ho progettato partitioning scheme prima che diventasse una feature da marketing deck.\nOracle non è un database che si impara sui tutorial.\nSi impara sugli incidenti, sulle migrazioni alle tre di notte, sui piani di esecuzione che cambiano dopo un aggiornamento delle statistiche.\nIn questa sezione racconto quello che ho imparato sul campo: architettura, sicurezza, performance e le decisioni progettuali che separano un\u0026rsquo;installazione che funziona da una che sopravvive.\nPerché con Oracle non basta sapere la sintassi.\nBisogna capire come ragiona il motore.\n","date":null,"permalink":"https://ivanluminaria.com/it/posts/oracle/","section":"Database Strategy","summary":"\u003cp\u003eOracle è il database che mi ha formato professionalmente.\u003cbr\u003e\nCi lavoro dal 1996, e in quasi trent\u0026rsquo;anni ho visto passare versioni, paradigmi e mode — ma il cuore del motore è rimasto lo stesso: solido, complesso, spietato con chi non lo conosce a fondo.\u003cbr\u003e\u003c/p\u003e\n\u003cp\u003eHo gestito istanze da poche centinaia di utenti e data warehouse da miliardi di righe. Ho configurato Data Guard quando ancora si chiamava standby database, ho scritto PL/SQL quando il debugging significava DBMS_OUTPUT e pazienza, ho progettato partitioning scheme prima che diventasse una feature da marketing deck.\u003cbr\u003e\u003c/p\u003e","title":"Oracle"},{"content":"La prima volta che ho lavorato con un cliente internazionale, mi è successa una cosa strana. Mi hanno pagato a trenta giorni.\nNon trenta giorni dalla fine del mese. Non trenta giorni dalla data di ricezione fattura protocollata e vidimata dal responsabile amministrativo. Trenta giorni dalla fattura. Punto.\nHo controllato l\u0026rsquo;estratto conto due volte. Ho pensato a un errore.\nNon era un errore. Era la normalità — solo che non era la normalità italiana.\n🇮🇹 La normalità italiana: aspettare è il mestiere #In Italia, se sei un consulente IT a partita IVA, il ciclo di pagamento funziona più o meno così:\nLavori a ottobre. Fatturi a fine ottobre. La fattura entra nel ciclo amministrativo del cliente a novembre. Il cliente paga a \u0026ldquo;60 giorni fine mese\u0026rdquo; — che nella pratica significa fine gennaio. Se va bene. Se non c\u0026rsquo;è il blocco pagamenti di fine anno. Se l\u0026rsquo;ufficio amministrativo non ha \u0026ldquo;perso\u0026rdquo; la fattura. Se il responsabile ha firmato l\u0026rsquo;approvazione. Risultato: lavori a ottobre, vedi i soldi a febbraio. Quattro mesi.\nE non sto parlando di situazioni patologiche. Sto parlando della prassi contrattuale standard nella consulenza IT italiana. Contratti che riportano nero su bianco \u0026ldquo;pagamento a 60 giorni data fattura fine mese\u0026rdquo; o, peggio, \u0026ldquo;90 giorni data fattura fine mese\u0026rdquo;.\nHo visto contratti a 120 giorni. Centoventì giorni. Quattro mesi dichiarati per contratto, che nella realtà diventano cinque o sei. Firmati senza battere ciglio, perché \u0026ldquo;funziona così\u0026rdquo; e perché il consulente che protesta è il consulente che non viene richiamato.\n🇪🇺 Cosa dice l\u0026rsquo;Europa (e cosa l\u0026rsquo;Italia finge di non sentire) #La Direttiva Europea 2011/7/UE sui ritardi di pagamento nelle transazioni commerciali è chiara. Cristallina, direi:\nRegola Cosa prevede Termine standard 30 giorni dalla data di fattura Termine massimo tra imprese 60 giorni (solo con accordo esplicito e se non gravemente iniquo) Termine per la Pubblica Amministrazione 30 giorni (estendibili a 60 solo in casi eccezionali) Interessi di mora automatici Tasso BCE + 8% — senza bisogno di messa in mora Compenso forfettario per il recupero 40€ minimo per ogni fattura pagata in ritardo Trenta giorni. Non novanta. Non centoventi. Trenta.\nLa direttiva è stata recepita in Italia con il D.Lgs. 231/2002 (modificato nel 2012). Sulla carta, le regole ci sono. Nella pratica, è come se non esistessero.\n🇩🇪 Come funziona nel resto d\u0026rsquo;Europa #Quando racconto ai colleghi tedeschi, olandesi o scandinavi che in Italia i tempi di pagamento standard sono 60-90 giorni, la reazione è sempre la stessa: prima lo stupore, poi una risata nervosa.\nIn Germania il termine di pagamento medio è di 24 giorni. Non perché i tedeschi siano più generosi — perché il sistema lo impone. Un pagamento oltre i 30 giorni genera automaticamente interessi di mora. Le aziende lo sanno e pagano.\nNei Paesi Bassi il termine medio è di 27 giorni. L\u0026rsquo;associazione di categoria MKB-Nederland pubblica ogni anno statistiche sui ritardi e le aziende che non rispettano i termini finiscono in liste pubbliche.\nNei paesi nordici — Svezia, Danimarca, Finlandia — pagare a 14 giorni è normale. A 30 è già considerato lungo.\nE l\u0026rsquo;Italia? Il termine medio effettivo di pagamento in Italia è di 80 giorni secondo l\u0026rsquo;European Payment Report. Ottanta. Quasi tre volte la media europea.\nPaese Termine medio di pagamento (giorni) Svezia 27 Germania 24 Paesi Bassi 27 Francia 44 Spagna 56 Italia 80 Termine massimo Direttiva UE 60 L\u0026rsquo;Italia non solo è fuori scala rispetto al nord Europa. È fuori scala rispetto alla propria legge.\n💰 L\u0026rsquo;impatto reale su chi lavora #Facciamo un esempio concreto. Un consulente IT senior che fattura 250€ al giorno, 220 giorni lavorativi all\u0026rsquo;anno.\nFatturato annuo lordo: 55.000€.\nCon pagamenti a 30 giorni, il flusso di cassa è gestibile. Ogni mese entra il lavoro del mese precedente. Il consulente può pianificare, investire, pagare le proprie tasse senza andare in rosso.\nCon pagamenti a 90 giorni fine mese, il quadro cambia radicalmente:\nMese Lavoro svolto Incassato Credito in sospeso Gennaio 5.500€ 0€ 5.500€ Febbraio 5.500€ 0€ 11.000€ Marzo 5.500€ 0€ 16.500€ Aprile 5.500€ 0€ 22.000€ Maggio 5.500€ 5.500€ 22.000€ Per i primi quattro mesi dell\u0026rsquo;anno il consulente lavora a credito. Sedici-ventimila euro di lavoro svolto e non pagato. Nel frattempo, le tasse non aspettano. I contributi INPS non aspettano. L\u0026rsquo;affitto non aspetta.\nQuel consulente sta finanziando il suo cliente. Gratis. Senza interessi. Senza garanzie.\nSe ci pensi, è un prestito. Solo che nessuno lo chiama così. Lo chiamano \u0026ldquo;termini contrattuali\u0026rdquo;.\n🏦 Il meccanismo perverso: chi paga finanzia chi incassa #Il paradosso è strutturale. Le grandi aziende di consulenza — quelle con centinaia di dipendenti e fatturati a sette cifre — negoziano termini lunghi con i fornitori (cioè i consulenti) e termini più brevi con i clienti finali. La differenza tra incasso e pagamento diventa un float finanziario che l\u0026rsquo;azienda usa come liquidità a costo zero.\nIl consulente freelance è l\u0026rsquo;anello più debole della catena. Non ha potere negoziale, non ha un ufficio legale, non ha alternative immediate. Accetta i 90 giorni perché il mercato funziona così e perché rifiutare significa restare senza progetti.\nHo visto situazioni ancora più creative:\nContratti che prevedono \u0026ldquo;90 giorni dalla data di approvazione del timesheet\u0026rdquo; — dove l\u0026rsquo;approvazione arriva con settimane di ritardo Fatture \u0026ldquo;bloccate\u0026rdquo; per errori formali inventati, per spostare il pagamento al ciclo successivo Pagamenti frazionati senza motivo apparente, con il saldo finale che arriva dopo sei mesi Non sono eccezioni. Sono tattiche consolidate. Ogni consulente italiano con un po\u0026rsquo; di esperienza le riconosce al volo.\n⚖️ Perché nessuno fa valere la legge #La domanda legittima è: se la legge prevede 30 giorni e gli interessi di mora sono automatici, perché nessuno li chiede?\nLa risposta è semplice e amara: perché il costo reputazionale è più alto del costo finanziario.\nUn consulente che manda una richiesta formale di interessi di mora al suo cliente è un consulente che non verrà più chiamato. Non perché abbia torto — ha ragione, legalmente e moralmente. Ma perché il mercato della consulenza IT in Italia è un mercato di relazioni, e in un mercato di relazioni chi fa valere i propri diritti viene percepito come \u0026ldquo;difficile\u0026rdquo;.\nÈ lo stesso meccanismo per cui nessuno chiede lo straordinario pagato, nessuno rifiuta la trasferta del venerdì sera e nessuno contesta la tariffa che scende a ogni rinnovo contrattuale.\nIl sistema si regge sulla docilità strutturale del consulente. E funziona, finché funziona.\n🛠️ Cosa si può fare concretamente #Non ho soluzioni magiche. Ma ho strategie che uso da anni e che funzionano — o almeno limitano i danni.\n1. Negoziare i termini PRIMA di firmare #Sembra ovvio, eppure la maggior parte dei consulenti firma il contratto senza leggere la clausola di pagamento. Il momento per negoziare è prima, non dopo. Un \u0026ldquo;pagamento a 30 giorni data fattura\u0026rdquo; scritto nel contratto vale più di qualsiasi protesta successiva.\n2. Inserire una clausola di interessi di mora esplicita #Anche se la legge li prevede automaticamente, scriverli nel contratto ha un effetto deterrente. Il cliente sa che non stai scherzando. Io uso una formula semplice: \u0026ldquo;In caso di ritardato pagamento si applicano gli interessi di mora ai sensi del D.Lgs. 231/2002, pari al tasso BCE + 8 punti percentuali.\u0026rdquo;\n3. Diversificare i clienti #Il consulente con un solo cliente è il consulente più vulnerabile. Se il 100% del tuo fatturato dipende da chi ti paga a 120 giorni, non hai leva negoziale. Se hai tre clienti e uno paga in ritardo cronico, puoi permetterti di lasciarlo.\n4. Valutare il cliente anche sulla puntualità di pagamento #Prima di accettare un incarico, chiedi ai colleghi. Il mondo della consulenza IT è piccolo. Chi paga male si sa. Chi paga bene, anche. Io tengo una lista mentale — e non è corta.\n5. Considerare i clienti internazionali #Non per patriottismo al contrario, ma per pragmatismo. I clienti del nord Europa pagano meglio, pagano prima e hanno processi amministrativi più trasparenti. Con il remote working, lavorare per un\u0026rsquo;azienda olandese da Roma non è più fantascienza. È il mio martedì.\n📊 Un confronto che fa riflettere #Prendiamo lo stesso consulente IT — stesse competenze, stessa seniority, stesso tipo di progetto. Cambia solo il paese del cliente.\n🇮🇹 Cliente italiano 🇩🇪 Cliente tedesco Tariffa giornaliera 250€ 450€ Termine di pagamento contrattuale 90 gg fine mese 30 gg Pagamento effettivo medio ~120 giorni ~28 giorni Interessi di mora richiesti mai (per paura) non servono (pagano puntuali) Processo di approvazione fattura labirintico un\u0026rsquo;email di conferma Rinnovo contrattuale \u0026ldquo;ti facciamo sapere\u0026rdquo; pianificato con 3 mesi di anticipo Non dico che lavorare con clienti italiani sia sempre peggio. Dico che i numeri raccontano una storia precisa, e che ignorarla per quieto vivere non è professionalità. È rassegnazione.\n💬 Una questione di rispetto #Il ritardo di pagamento cronico non è solo un problema finanziario. È un problema di rispetto professionale.\nQuando un\u0026rsquo;azienda paga un consulente a 120 giorni, gli sta dicendo: \u0026ldquo;Il tuo tempo e il tuo lavoro possono aspettare. I nostri tempi vengono prima dei tuoi.\u0026rdquo;\nÈ lo stesso messaggio che passa quando ti chiedono di iniziare \u0026ldquo;lunedì\u0026rdquo; ma il contratto arriva dopo tre settimane. Quando il timesheet deve essere compilato al minuto ma la fattura può restare in un cassetto per mesi. Quando il progetto è urgentissimo ma il pagamento no.\nHo trent\u0026rsquo;anni di consulenza alle spalle. Ho lavorato con clienti che mi hanno pagato a 14 giorni e clienti che ci hanno messo otto mesi. La qualità del rapporto professionale non è mai stata una questione di budget. È sempre stata una questione di come trattano chi lavora per loro.\nI clienti migliori che ho avuto pagavano puntualmente. Non per generosità — per organizzazione. Perché un\u0026rsquo;azienda che sa gestire i propri pagamenti è un\u0026rsquo;azienda che sa gestire i propri progetti. E viceversa.\nChi paga male, quasi sempre, gestisce male anche tutto il resto.\nGlossario #DSO — Days Sales Outstanding — numero medio di giorni che un\u0026rsquo;azienda impiega per incassare i propri crediti. In Italia la media è di 80 giorni, quasi tre volte la media europea.\nFloat Finanziario — Liquidità a costo zero generata dalla differenza tra i tempi di incasso dai clienti e i tempi di pagamento ai fornitori.\nInteressi di Mora — Interessi automatici previsti dalla legge (tasso BCE + 8%) che maturano su ogni fattura pagata in ritardo, senza bisogno di messa in mora.\nPartita IVA — Regime fiscale italiano per lavoratori autonomi e liberi professionisti, che nella consulenza IT implica l\u0026rsquo;assunzione diretta del rischio di credito.\nDirettiva 2011/7/UE — Direttiva europea sui ritardi di pagamento che fissa il termine standard a 30 giorni, il massimo a 60, e prevede interessi di mora automatici.\n","date":"10 marzo 2026","permalink":"https://ivanluminaria.com/it/posts/project-management/pagamenti-60-90-120-giorni/","section":"Database Strategy","summary":"\u003cp\u003eLa prima volta che ho lavorato con un cliente internazionale, mi è successa una cosa strana. Mi hanno pagato a trenta giorni.\u003c/p\u003e\n\u003cp\u003eNon trenta giorni dalla fine del mese. Non trenta giorni dalla data di ricezione fattura protocollata e vidimata dal responsabile amministrativo. Trenta giorni dalla fattura. Punto.\u003c/p\u003e\n\u003cp\u003eHo controllato l\u0026rsquo;estratto conto due volte. Ho pensato a un errore.\u003c/p\u003e\n\u003cp\u003eNon era un errore. Era la normalità — solo che non era la normalità italiana.\u003c/p\u003e","title":"Pagamenti a 60-90-120 giorni: la normalità italiana che in Europa non esiste"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/payments/","section":"Tags","summary":"","title":"Payments"},{"content":"Scarica PDF | Profilo LinkedIn\nProfilo Professionale #Data Warehouse Architect e professionista IT con quasi 30 anni di esperienza nella progettazione, implementazione e gestione di soluzioni DWH complesse e ad alte prestazioni in ambienti Oracle e PostgreSQL. Esperto in metodologie di modellazione multidimensionale dei dati (Kimball, Inmon) e nell\u0026rsquo;ottimizzazione di processi ETL/ELT e query SQL su dataset che vanno da centinaia di milioni a miliardi di righe. Comprovata capacità di guidare progetti DWH end-to-end — dall\u0026rsquo;analisi dei requisiti al deployment in produzione — garantendo integrità, qualità e disponibilità dei dati a supporto delle decisioni di business. Leadership tecnica e mentalità orientata al problem-solving in contesti internazionali e full-remote.\nCompetenze Tecniche # Metodologie DWH: Modellazione Multidimensionale dei Dati (Kimball, Inmon), Star Schema, Snowflake Schema, Slowly Changing Dimensions (SCD Type 1/2/3), Bus Matrix design. Oracle Databases: Oracle Database (dalla 8i alla 21c), Oracle Exadata, Oracle RAC, Oracle Data Guard, Oracle Autonomous Database (ADB), Performance Tuning (AWR, ADDM, SQL Tuning Advisor), Storage Management (ASM), Backup \u0026amp; Recovery (RMAN), Oracle TDE. PostgreSQL: PostgreSQL (14+), Query Optimization, Table Partitioning, pg_stat_statements, PgBouncer, Logical Replication, VACUUM/Autovacuum tuning. Cloud: Oracle Cloud Infrastructure (OCI). Strumenti ETL/ELT: Pipeline ETL basate su PL/SQL, Unix Shell Scripting, Oracle Data Integrator (ODI), Oracle Warehouse Builder (OWB, progetti legacy). Business Intelligence \u0026amp; Reporting: Oracle Analytics Cloud (OAC) — Semantic Model Designer, Reports, Dashboard. Linguaggi di Programmazione e Scripting: SQL (avanzato), PL/SQL, Unix Shell Scripting. Sistemi Operativi: Linux (RHEL, CentOS, Oracle Linux), Unix, Windows Server. Altro: Project Management (Agile/Scrum), Team Leadership (fino a 7 persone), Formazione Tecnica. Esperienza Professionale #IDEA DB CONSULTING S.R.L. — Roma, Italia (Full Remote Europa) #Data Warehouse Architect | Oracle \u0026amp; PostgreSQL Expert | Amministratore Unico | 2021 – Presente\nDWH Architect (per ATRADIUS) | 2022 – 2026:\nProgettazione del Data Warehouse della divisione Surety per il consolidamento dei dati provenienti da Italia, Spagna, Francia e paesi del Nord Europa. Integrazione di sorgenti eterogenee — database Oracle, Microsoft SQL Server e file flat da sistemi esterni — in un DWH unificato basato su Oracle. Modellazione dei domini di business principali: portafoglio clienti, polizze, contratti, fatturazione, sinistri e transazioni sui sinistri. Sviluppo dell\u0026rsquo;intero data model e layer ETL — oltre 60.000 righe di codice PL/SQL — con un sistema di monitoraggio dei caricamenti in tempo reale. L\u0026rsquo;ingestione giornaliera completa da tutte e tre le sorgenti si completa in meno di 2 ore. DWH Architect (per FAI SERVICE) | 2021 – 2023:\nProgettazione di un data model Snowflake Schema su Oracle Analytics Cloud con processi ETL su Oracle 19c in OCI. Sviluppo di dashboard e report su OAC per statistiche di fatturazione, segmentazione clienti, analisi del portafoglio e tracking costi/ricavi. Progettazione e Architettura DWH (Banking, Telepass e altri clienti):\nDefinizione e implementazione di architetture Data Warehouse per clienti del settore bancario e partner Telepass, seguendo le metodologie Kimball e Inmon. Applicazione della modellazione multidimensionale (Star Schema, Snowflake) per ottimizzare analisi e reporting su dataset superiori ai 2 miliardi di righe. Progettazione e sviluppo di flussi ETL/ELT per l\u0026rsquo;integrazione di dati da oltre 15 sorgenti eterogenee. Progettazione e implementazione di soluzioni DWH su PostgreSQL come alternative cost-effective alle architetture Oracle, incluse strategie di partizionamento e ottimizzazione delle prestazioni delle query. Gestione e Ottimizzazione Database Oracle:\nAmministrazione avanzata, tuning e ottimizzazione delle prestazioni di database Oracle, inclusi ambienti OCI e Autonomous Database. Ottimizzazione di query SQL complesse — riduzione dei tempi di elaborazione batch da 4 ore a meno di 30 minuti su workload analitici critici. Leadership e Consulenza:\nGuida tecnica e formazione per team interni e clienti sulle best practice DWH e Oracle/PostgreSQL. Installazione e patching di database Oracle, gestione Oracle OEM e RMAN. Sviluppo di report e dashboard con Oracle Analytics Cloud (OAC). NIMIS CONSULTING S.R.L. — Roma, Italia (Full Remote) #Oracle DBA | DWH Architect | Oracle Performance \u0026amp; Tuning Expert (per TIM / HUAWEI) | 2020 – 2022\nAmministrazione Progetto DWH/DBA:\nGestione e amministrazione di oltre 30 database Oracle critici (70+ istanze) su cluster Oracle Exadata (3 e 5 nodi) per un importante cliente Telco. Responsabile della reperibilità 24/7 dei sistemi database a supporto di oltre 20 milioni di abbonati mobile prepagati. Gestione di tabelle dei fatti con ingestione fino a 800 milioni di record di traffico telefonico al giorno, con strategie avanzate di partizionamento e compressione. Performance Tuning Avanzato:\nAnalisi approfondita delle prestazioni tramite AWR, ADDM e tuning proattivo per garantire SLA sotto i 500ms di tempo di risposta sulle query critiche. Implementazione di strategie di indicizzazione, partizionamento e compressione per migliorare le prestazioni del sistema DWH. Gestione della sicurezza dei dati con Oracle TDE (Transparent Data Encryption). IDEA DB CONSULTING S.R.L. — Roma, Italia (Full Remote) #PL/SQL Expert | Oracle DBA \u0026amp; Tuning Expert (per FINWAVE S.p.A.) | 2020 – 2022\nSviluppo avanzato PL/SQL e ottimizzazione delle query per applicazioni finanziarie che elaborano milioni di transazioni giornaliere. Consulenza su architetture Oracle e best practice di performance tuning. LIBERO PROFESSIONISTA / CONSULENTE INDIPENDENTE — Roma, Italia (Full Remote Europa) #Oracle DBA | Oracle Performance \u0026amp; Tuning Expert | DWH Architect | 2013 – 2020\nProgettazione e sviluppo di Data Warehouse per clienti nei settori bancario, assicurativo e telecomunicazioni, applicando metodologie Kimball/Inmon su piattaforme Oracle e PostgreSQL. Sviluppo di processi ETL/ELT per il caricamento dati DWH — costruzione di pipeline che gestiscono oltre 500 milioni di righe per ciclo di caricamento. Consulenza specializzata su database Oracle e PostgreSQL, SQL performance tuning, architetture DWH, PL/SQL e progettazione ETL. Leadership di team (3-7 persone) in contesti multiculturali, gestione di attività e priorità con metodologia Agile. Creazione di report e analisi dati con Oracle Analytics Cloud (OAC). AUSELDA AED GROUP S.P.A. — Roma, Italia #Data Warehouse Architect | Performance \u0026amp; Tuning Expert | Oracle Project DBA (per la Pubblica Amministrazione) | 2009 – 2013\nProgettazione e modellazione Data Warehouse (Kimball/Inmon) per enti della Pubblica Amministrazione. Sviluppo di processi ETL/ELT e ottimizzazione di query SQL complesse. Specialista del prodotto Oracle Warehouse Builder (OWB). Gestione tecnica dei progetti DWH e formazione utenti. ORACLE ITALIA S.R.L. — Varie sedi, Italia \u0026amp; Madrid, Spagna #Data Warehouse Architect | Oracle DBA | DWH Designer | SQL \u0026amp; PL/SQL Developer | Training Specialist | 1999 – 2009\nRuoli architetturali e di sviluppo DWH (2001-2009):\nProgettazione e sviluppo di Data Warehouse per clienti primari nel Telco (TIM, Vodafone, TRE), Finance (Banca d\u0026rsquo;Italia, Generali, RAS), Farmaceutico (Menarini) e altri settori. Implementazione di data model (Kimball/Inmon) e processi ETL/ELT con Oracle Warehouse Builder. Consulenza su SQL Performance \u0026amp; Tuning, PL/SQL, BI Reports (Oracle Discoverer, HTMLDB), Oracle OLAP. Esperienza internazionale con Vodafone Spagna (Madrid). Training Specialist (2000-2001):\nErogazione corsi Oracle: SQL (Base e Avanzato), PL/SQL (Base e Avanzato), Oracle Database Administration, Performance and Tuning, Oracle Discoverer, Forms, Reports. Web Developer | Oracle SQL \u0026amp; PL/SQL Developer (ETNOTEAM S.P.A. - 1999): Sviluppo di portali web e applicazioni client-server.\nS.EL.DAT. S.P.A. — Roma, Italia #Software Developer (per Telecom, Rover Italia) | 1997 – 1999\nSviluppo applicazioni client-server, Junior Oracle DBA, monitoraggio DB. Formazione # Facoltà di Ingegneria Informatica (Ingegneria del Software) | Università degli Studi Roma Tre, Roma | 1994 – 2000 Diploma di Maturità Scientifica (EQF Livello 4) | Liceo Scientifico Isacco Newton / Manieri Copernico, Roma | 1988 – 1993 Inglese Avanzato (C1/C2) | The British Council (Livello 4A), Roma | 2003 – 2004 Corsi di Formazione e Aggiornamento Selezionati:\nScrum Agile — Randstad/Forma.temp (Maggio 2024) Project Management — Randstad/Forma.temp (Maggio 2024) Data Wrangling, Analysis and AB Testing with SQL — Coursera, University of California Davis (Aprile 2021) Data Science on Google Cloud Platform: Designing Data Warehouses — LinkedIn Learning (Settembre 2020) Corsi di specializzazione Oracle 12c (Administration, Security, Backup and Recovery, Advanced SQL, Performance Optimization) — LinkedIn Learning (2020) MySQL Installation and Configuration — LinkedIn Learning (Agosto 2020) Learning Git and GitHub — LinkedIn Learning (Agosto 2020) Lingue # Italiano: Madrelingua Inglese: C1/C2 (Fluente, professionale) Spagnolo: C1 (Fluente) Rumeno: C1 (Fluente) Francese: A1/A2 (Base) Competenze Trasversali # Problem Solving analitico e creativo Lavoro di squadra e collaborazione in contesti internazionali Project Management (Definizione requisiti, Prioritizzazione, Diagrammi di Gantt, ERD) Comunicazione efficace e coinvolgimento degli stakeholder Autorizzo il trattamento dei miei dati personali ai sensi dell\u0026rsquo;Art. 13 del Regolamento UE 2016/679 (GDPR).\nRoma, Marzo 2026\nScarica PDF | Profilo LinkedIn | Torna alla pagina precedente\n","date":"10 marzo 2026","permalink":"https://ivanluminaria.com/it/resumes/dwh-architect/","section":"Know-How e Impatto","summary":"\u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://ivanluminaria.com/downloads/CV_DWH_Architect_Ivan_Luminaria_202603_EN.pdf\" target=\"_blank\" rel=\"noreferrer\"\u003eScarica PDF\u003c/a\u003e\u003c/strong\u003e | \u003cstrong\u003e\u003ca href=\"https://www.linkedin.com/in/ivanluminaria\" target=\"_blank\" rel=\"noreferrer\"\u003eProfilo LinkedIn\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"profilo-professionale\" class=\"relative group\"\u003eProfilo Professionale \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#profilo-professionale\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eData Warehouse Architect e professionista IT con quasi 30 anni di esperienza nella progettazione, implementazione e gestione di soluzioni DWH complesse e ad alte prestazioni in ambienti Oracle e PostgreSQL. Esperto in metodologie di modellazione multidimensionale dei dati (Kimball, Inmon) e nell\u0026rsquo;ottimizzazione di processi ETL/ELT e query SQL su dataset che vanno da centinaia di milioni a miliardi di righe. Comprovata capacità di guidare progetti DWH end-to-end — dall\u0026rsquo;analisi dei requisiti al deployment in produzione — garantendo integrità, qualità e disponibilità dei dati a supporto delle decisioni di business. Leadership tecnica e mentalità orientata al problem-solving in contesti internazionali e full-remote.\u003c/p\u003e","title":"Data Warehouse Architect"},{"content":"Scarica PDF | Profilo LinkedIn\nProfilo Professionale #Senior Oracle DBA e Performance Tuning Expert con quasi 30 anni di esperienza specializzata nell\u0026rsquo;amministrazione, ottimizzazione e gestione di database Oracle complessi e mission-critical, inclusi ambienti Exadata, RAC e Oracle Cloud (OCI, Autonomous Database). Profonda competenza nell\u0026rsquo;analisi delle prestazioni (AWR, ADDM, ASH), nel tuning di query SQL complesse, nell\u0026rsquo;ottimizzazione delle istanze e nella risoluzione di problemi di performance. Conoscenze consolidate nelle pratiche di backup \u0026amp; recovery (RMAN), sicurezza (TDE), installazione, patching, migrazioni e gestione dello storage (ASM), con il performance tuning come area primaria e approfondita di competenza, cruciale per l\u0026rsquo;integrità, le prestazioni e il contributo all\u0026rsquo;alta disponibilità dei sistemi Oracle in contesti aziendali internazionali e ad elevata complessità.\nCompetenze Tecniche — Oracle DBA \u0026amp; Performance Tuning # Oracle Database Administration: Oracle Database (dalla 8i alla 21c, Autonomous), Oracle Exadata, Oracle RAC (Real Application Clusters), Oracle Data Guard, Oracle GoldenGate (conoscenza di base). Performance Tuning Avanzato: Analisi e Diagnostica: AWR, ADDM, ASH, Statspack, SQL Trace, TKPROF, Explain Plan. SQL Tuning: Ottimizzazione di query complesse, Hints, SQL Profiles, SQL Plan Management (SPM). Instance Tuning: Memory Management (SGA, PGA), parametri di inizializzazione, analisi dei Wait Events. Database Design per le Prestazioni: Indicizzazione (B-tree, Bitmap, Function-based), Partizionamento (Range, List, Hash, Composite), Compressione. Alta Disponibilità e Disaster Recovery: RMAN (Backup, Recovery, Cloning), Oracle Data Guard, Flashback Technologies. Sicurezza del Database: Oracle TDE (Transparent Data Encryption), gestione utenti e privilegi, Auditing. Gestione dello Storage: ASM (Automatic Storage Management), gestione dei Tablespace. Installazione, Patching e Migrazioni: Installazione di nuove istanze, applicazione di PSU/CPU/RU, upgrade di versione, migrazioni cross-platform. Strumenti Oracle: Oracle Enterprise Manager (OEM) Cloud Control, SQL Developer, SQL*Plus, Toad. Scripting: PL/SQL, SQL, Unix Shell Scripting (per automazione di attività DBA). Cloud: Oracle Cloud Infrastructure (OCI) — Compute, Storage, Networking, Database Services (VM DB, Bare Metal, Exadata CS, Autonomous Database). Altre Tecnologie Database: PostgreSQL (amministrazione, performance tuning, partizionamento, replica), MySQL (amministrazione, configurazione, replica, ottimizzazione InnoDB). Sistemi Operativi: Linux (Red Hat, Oracle Linux), Unix (AIX, Solaris), Windows Server. Esperienza Professionale #IDEA DB CONSULTING S.R.L. — Roma, Italia (Full Remote Europa) #Senior Oracle DBA \u0026amp; Performance Tuning Expert / DWH Architect | Amministratore Unico | 2021 – Presente\nDBA MySQL \u0026amp; PostgreSQL (per POSTE ITALIANE) | Lug 2025 – Presente:\nAmministrazione e gestione di circa 1.500 istanze MySQL e PostgreSQL in ambienti di produzione, staging e sviluppo. Monitoraggio delle prestazioni, query tuning, gestione della replica e capacity planning su scala enterprise. Oracle DBA \u0026amp; Tuning Expert (per GENERALI Assicurazioni) | Feb 2024 – Mag 2025:\nAmministrazione di database Oracle e performance tuning avanzato per applicazioni del settore assicurativo. Analisi AWR/ADDM, ottimizzazione SQL e risoluzione proattiva dei colli di bottiglia su database da 500GB a 8TB. Oracle DBA (per ATRADIUS) | 2022 – 2026:\nAmministrazione e performance tuning dei database a supporto del Data Warehouse della divisione Surety per il consolidamento dati da Italia, Spagna, Francia e paesi del Nord Europa. Gestione di database Oracle in ambienti OCI, a supporto di oltre 60.000 righe di codice PL/SQL ETL con ingestione giornaliera completa in meno di 2 ore. Oracle DBA (per FAI SERVICE) | 2021 – 2023:\nAmministrazione e tuning di database Oracle 19c in OCI a supporto di processi ETL e dashboard Oracle Analytics Cloud. DBA \u0026amp; Performance Tuning (Banking, Telepass e altri clienti):\nOttimizzazione di database Oracle in ambienti OCI e Autonomous Database — riduzione dei tempi di elaborazione batch da 4 ore a meno di 30 minuti su workload analitici critici. Progettazione e sviluppo di flussi ETL/ELT per l\u0026rsquo;integrazione dati da oltre 15 sorgenti eterogenee su dataset superiori ai 2 miliardi di righe. Gestione RMAN, monitoraggio Oracle OEM, installazione e patching di database Oracle. Progettazione e implementazione di soluzioni DWH su PostgreSQL come alternative cost-effective alle architetture Oracle. NIMIS CONSULTING S.R.L. — Roma, Italia (Full Remote) #Senior Oracle DBA \u0026amp; Performance Tuning Expert (per TIM / HUAWEI) | 2020 – 2022\nAmministrazione e gestione di oltre 30 database Oracle critici (70+ istanze) su cluster Oracle Exadata (3/5 nodi) per un importante cliente Telco. Responsabilità diretta per il performance tuning avanzato: analisi AWR/ADDM, ottimizzazione SQL, gestione degli indici, partizionamento e compressione. Coinvolgimento in attività di gestione dello storage (ASM) e implementazione di Oracle TDE per la sicurezza dei dati. Supporto \u0026ldquo;ON-CALL\u0026rdquo; 24/7 per la risoluzione di problemi critici e il mantenimento dell\u0026rsquo;alta disponibilità. LIBERO PROFESSIONISTA / CONSULENTE INDIPENDENTE — Roma, Italia (Full Remote Europa) #Senior Oracle DBA \u0026amp; Performance Tuning Expert / DWH Architect | 2013 – 2020\nErogazione di servizi di consulenza come Oracle DBA e specialista in Performance Tuning per diversi clienti. Ottimizzazione di query SQL complesse e tuning di istanze Oracle per migliorare le prestazioni di applicazioni critiche. Supporto all\u0026rsquo;installazione, configurazione, patching e upgrade di database Oracle. Consulenza sulle strategie di backup e recovery con RMAN. Progettazione e implementazione di configurazioni Oracle Data Guard per alta disponibilità e disaster recovery, incluse procedure di switchover/failover. Gestione di piccoli team tecnici in progetti di migrazione e upgrade. AUSELDA AED GROUP S.P.A. — Roma, Italia #Project Oracle DBA / Performance \u0026amp; Tuning Expert (per la Pubblica Amministrazione) | 2009 – 2013\nAmministrazione e ottimizzazione di database Oracle a supporto di applicazioni per la Pubblica Amministrazione. Tuning di query SQL e processi ETL per sistemi di Data Warehousing. Coinvolgimento in attività di installazione, patching e gestione della sicurezza del database. ORACLE ITALIA S.R.L. — Varie sedi, Italia \u0026amp; Madrid, Spagna #Oracle DBA / DWH Architect / SQL \u0026amp; PL/SQL Developer / Training Specialist | 1999 – 2009\nRuoli DBA e Performance (progressivamente crescenti): Amministrazione di database Oracle per clienti enterprise (TIM, Vodafone, Banca d\u0026rsquo;Italia, Generali). Coinvolgimento in attività di SQL Performance \u0026amp; Tuning, troubleshooting e ottimizzazione. Supporto all\u0026rsquo;installazione e configurazione di istanze Oracle, gestione delle patch. Come Training Specialist (2000-2001): Erogazione di corsi su Oracle Database Administration e Performance \u0026amp; Tuning. S.EL.DAT. S.P.A. — Roma, Italia #Software Developer (per Telecom, Rover Italia) | 1997 – 1999\nSviluppo applicazioni client-server, Junior Oracle DBA, monitoraggio DB. Formazione # Facoltà di Ingegneria Informatica (Ingegneria del Software) | Università degli Studi Roma Tre, Roma | 1994 – 2000 Diploma di Maturità Scientifica (EQF Livello 4) | Liceo Scientifico Isacco Newton / Manieri Copernico, Roma | 1988 – 1993 Inglese Avanzato (C1/C2) | The British Council (Livello 4A), Roma | 2003 – 2004 Corsi di Formazione e Aggiornamento Selezionati:\nAdvanced SQL for Query Tuning and Performance Optimization — LinkedIn Learning (Agosto 2020) Data Wrangling, Analysis and AB Testing with SQL — Coursera, University of California Davis (Aprile 2021) Corsi di specializzazione Oracle 12c (Administration, Security, Backup and Recovery, Advanced SQL, New Features) — LinkedIn Learning (2020) Lingue # Italiano: Madrelingua Inglese: C1/C2 (Fluente, professionale) Spagnolo: C1 (Fluente) Rumeno: C1 (Fluente) Francese: A1/A2 (Base) Competenze Trasversali # Problem Solving analitico e metodico Gestione delle priorità e rispetto delle scadenze Capacità di lavorare sotto pressione Comunicazione tecnica chiara ed efficace Attenzione ai dettagli e precisione Apprendimento continuo e adattabilità tecnologica Autorizzo il trattamento dei miei dati personali ai sensi dell\u0026rsquo;Art. 13 del Regolamento UE 2016/679 (GDPR).\nRoma, Marzo 2026\nScarica PDF | Profilo LinkedIn | Torna alla pagina precedente\n","date":"10 marzo 2026","permalink":"https://ivanluminaria.com/it/resumes/oracle-dba/","section":"Know-How e Impatto","summary":"\u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://ivanluminaria.com/downloads/CV_Oracle_DBA_Ivan_Luminaria_202603_EN.pdf\" target=\"_blank\" rel=\"noreferrer\"\u003eScarica PDF\u003c/a\u003e\u003c/strong\u003e | \u003cstrong\u003e\u003ca href=\"https://www.linkedin.com/in/ivanluminaria\" target=\"_blank\" rel=\"noreferrer\"\u003eProfilo LinkedIn\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"profilo-professionale\" class=\"relative group\"\u003eProfilo Professionale \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#profilo-professionale\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSenior Oracle DBA e Performance Tuning Expert con quasi 30 anni di esperienza specializzata nell\u0026rsquo;amministrazione, ottimizzazione e gestione di database Oracle complessi e mission-critical, inclusi ambienti Exadata, RAC e Oracle Cloud (OCI, Autonomous Database). Profonda competenza nell\u0026rsquo;analisi delle prestazioni (AWR, ADDM, ASH), nel tuning di query SQL complesse, nell\u0026rsquo;ottimizzazione delle istanze e nella risoluzione di problemi di performance. Conoscenze consolidate nelle pratiche di backup \u0026amp; recovery (RMAN), sicurezza (TDE), installazione, patching, migrazioni e gestione dello storage (ASM), con il performance tuning come area primaria e approfondita di competenza, cruciale per l\u0026rsquo;integrità, le prestazioni e il contributo all\u0026rsquo;alta disponibilità dei sistemi Oracle in contesti aziendali internazionali e ad elevata complessità.\u003c/p\u003e","title":"Oracle DBA \u0026 Performance Tuning Expert"},{"content":"Scarica PDF | Profilo LinkedIn\nProfilo Professionale #Senior Oracle PL/SQL Developer con quasi 30 anni di esperienza nella progettazione, sviluppo, test e ottimizzazione di codice PL/SQL robusto ed efficiente per applicazioni data-intensive e sistemi di Data Warehouse. Profonda competenza nella creazione di package, procedure, funzioni, trigger e tipi complessi, con un focus costante su prestazioni, manutenibilità e qualità del codice. Esperto nell\u0026rsquo;ottimizzazione di query SQL complesse e nella gestione di grandi volumi di dati. Abile nel tradurre requisiti di business in logica applicativa performante e scalabile all\u0026rsquo;interno del database Oracle. Background consolidato anche come Oracle DBA e DWH Architect, che garantisce una visione completa del ciclo di vita del dato.\nCompetenze Tecniche — Sviluppo Oracle PL/SQL # Linguaggi: PL/SQL (Avanzato), SQL (Avanzato, inclusi Dynamic SQL, Analytic Functions, CTEs). Sviluppo PL/SQL: Package, Procedure, Funzioni, Trigger. Tipi di Dati PL/SQL (Record, Collection, Object Types). Gestione di Errori ed Eccezioni. Elaborazione Massiva (FORALL, BULK COLLECT). Dynamic SQL (DBMS_SQL, Execute Immediate). Ottimizzazione del Codice PL/SQL (incluso l\u0026rsquo;uso del PL/SQL Hierarchical Profiler). Interazione con Oggetti di Database (Tabelle, Viste, Sequence, Sinonimi). Ottimizzazione SQL \u0026amp; Performance: Analisi dei Piani di Esecuzione (Explain Plan), SQL Trace, TKPROF. Tecniche di SQL Tuning (Hints, Query Rewriting, Indici). Comprensione dell\u0026rsquo;impatto del database design sulle prestazioni PL/SQL. Strumenti di Sviluppo: SQL Developer, Toad, SQL*Plus. Oracle Database: Oracle Database (dalla 8i alla 21c, Autonomous Database). Concetti Correlati: Data Warehousing (sviluppo di logiche ETL/ELT), Data Integration, Modellazione Dati Relazionale e Multidimensionale. Version Control: Git, GitHub. Scripting: Unix Shell Scripting (per automazione di deployment e gestione script). Cloud: Oracle Cloud Infrastructure (OCI) — conoscenza dei servizi database. Esperienza Professionale #IDEA DB CONSULTING S.R.L. — Roma, Italia (Full Remote Europa) #Senior Oracle PL/SQL Developer \u0026amp; DWH Architect | 2022 – Presente\nPL/SQL Developer (per ATRADIUS) | 2022 – 2026:\nSviluppo e manutenzione di oltre 60.000 righe di codice PL/SQL (package, procedure, funzioni) per il Data Warehouse della divisione Surety, che consolida dati assicurativi e creditizi da Italia, Spagna, Francia e paesi del Nord Europa. Progettazione di template PL/SQL riutilizzabili per le procedure di caricamento dati — standardizzazione del workflow ETL interno con checkpoint integrati per il tracciamento e monitoraggio in tempo reale dei flussi di caricamento, consentendo anche a sviluppatori junior di seguire un pattern consistente e ripetibile. Implementazione di monitoraggio real-time dei caricamenti tramite package PL/SQL di logging personalizzati, con visibilità immediata sullo stato delle pipeline ETL e gestione errori in tutte le fasi di caricamento. Ottimizzazione delle prestazioni batch: riduzione del ciclo di ingestione giornaliera completa da 4+ ore a meno di 2 ore tramite riscrittura delle query, pattern BULK COLLECT/FORALL e DML partition-aware. PL/SQL Developer (per FINWAVE S.p.A.) | 2020 – 2022:\nSviluppo di package PL/SQL per applicazioni di elaborazione transazioni finanziarie che gestiscono milioni di operazioni giornaliere per clienti bancari e assicurativi. Ottimizzazione avanzata di query e tuning del codice PL/SQL per pipeline di dati finanziari ad alto volume. PL/SQL Developer (per FAI SERVICE) | 2021 – 2023:\nSviluppo di procedure ETL in PL/SQL su Oracle 19c/OCI per flussi dati di statistiche fatturazione, segmentazione clienti e tracciamento costi/ricavi. Costruzione di moduli PL/SQL che alimentano dashboard Oracle Analytics Cloud con KPI finanziari aggregati. Sviluppo PL/SQL (Banking, Telepass e altri clienti):\nSviluppo di package PL/SQL per logica di business in applicazioni DWH del settore bancario, con elaborazione di dataset superiori a 2 miliardi di righe. Ottimizzazione di codice PL/SQL e query SQL esistenti — utilizzo del Hierarchical Profiler per identificare colli di bottiglia e migliorare i tempi di esecuzione dei percorsi critici. Collaborazione con team di sviluppo e analisti funzionali per la definizione dei requisiti e la progettazione di soluzioni basate su PL/SQL. NIMIS CONSULTING S.R.L. — Roma, Italia (Full Remote) #Senior Oracle DBA \u0026amp; Performance Expert con Focus sullo Sviluppo (per TIM / HUAWEI) | 2020 – 2022\nSupporto specialistico ai team di sviluppo nell\u0026rsquo;ottimizzazione del codice PL/SQL e delle query SQL per applicazioni critiche su database Exadata. Analisi e tuning di processi batch PL/SQL ad alto volume. Sviluppo di script PL/SQL per attività di monitoraggio e amministrazione. LIBERO PROFESSIONISTA / CONSULENTE INDIPENDENTE — Roma, Italia (Full Remote Europa) #Senior Oracle PL/SQL Developer \u0026amp; DBA / DWH Architect | 2013 – 2020\nProgettazione e sviluppo di soluzioni PL/SQL personalizzate per diversi clienti, inclusi package per logiche ETL, procedure di elaborazione dati e API PL/SQL. Ottimizzazione intensiva di codice PL/SQL e SQL per migliorare le prestazioni di sistemi esistenti. Sviluppo di moduli PL/SQL per l\u0026rsquo;estrazione, la trasformazione e il caricamento (ETL) di dati in sistemi DWH. Formazione e mentoring di sviluppatori junior sulle best practice di sviluppo PL/SQL. AUSELDA AED GROUP S.P.A. — Roma, Italia #Oracle PL/SQL Developer \u0026amp; Specialista DWH (per la Pubblica Amministrazione) | 2009 – 2013\nSviluppo di componenti PL/SQL per sistemi di Data Warehousing e applicazioni gestionali per la Pubblica Amministrazione. Manutenzione evolutiva e correttiva di codice PL/SQL. Ottimizzazione di processi ETL basati su PL/SQL e OWB. ORACLE ITALIA S.R.L. — Varie sedi, Italia \u0026amp; Madrid, Spagna #SQL \u0026amp; PL/SQL Developer / DWH Architect / DBA / Training Specialist | 1999 – 2009\nRuoli di Sviluppo PL/SQL (significativi e crescenti): Sviluppo intensivo di codice PL/SQL per progetti DWH, BI e applicazioni personalizzate per clienti enterprise in diversi settori (Telco, Finance, Farmaceutico). Creazione di package PL/SQL per logiche di business complesse, procedure di caricamento dati (ETL) con Oracle Warehouse Builder e PL/SQL. Sviluppo di report BI e interfacce HTMLDB (Apex) con logica PL/SQL. Come Training Specialist (2000-2001): Erogazione di corsi Oracle SQL (Base e Avanzato) e PL/SQL (Base e Avanzato). ETNOTEAM S.P.A. — Roma, Italia #Web Developer / Oracle SQL \u0026amp; PL/SQL Developer | 1999\nSviluppo di portali web e applicazioni client-server con forte interazione con database Oracle, utilizzando SQL e PL/SQL per la logica di backend. S.EL.DAT. S.P.A. — Roma, Italia #Software Developer / Junior DBA | 1997 – 1999\nSviluppo di applicazioni client-server con backend Oracle; prime esperienze con SQL e PL/SQL. Formazione # Facoltà di Ingegneria Informatica (Ingegneria del Software) | Università degli Studi Roma Tre, Roma | 1994 – 2000 Diploma di Maturità Scientifica (EQF Livello 4) | Liceo Scientifico Isacco Newton / Manieri Copernico, Roma | 1988 – 1993 Inglese Avanzato (C1/C2) | The British Council (Livello 4A), Roma | 2003 – 2004 Corsi di Formazione e Aggiornamento Selezionati:\nScrum Agile — Randstad/Forma.temp (Maggio 2024) Project Management — Randstad/Forma.temp (Maggio 2024) Data Wrangling, Analysis and AB Testing with SQL — Coursera, University of California Davis (Aprile 2021) Advanced SQL for Query Tuning and Performance Optimization — LinkedIn Learning (Agosto 2020) Corsi di specializzazione Oracle 12c (Advanced SQL, New Features) — LinkedIn Learning (2020) Learning Git and GitHub — LinkedIn Learning (Agosto 2020) Lingue # Italiano: Madrelingua Inglese: C1/C2 (Fluente, professionale) Spagnolo: C1 (Fluente) Rumeno: C1 (Fluente) Francese: A1/A2 (Base) Competenze Trasversali # Approccio analitico e orientamento alla risoluzione di problemi complessi Scrittura di codice chiaro, efficiente e manutenibile Competenze avanzate di debugging e troubleshooting Eccellente comprensione dei requisiti funzionali e tecnici Collaborazione efficace nei team di sviluppo Attenzione ai dettagli e qualità del software Autorizzo il trattamento dei miei dati personali ai sensi dell\u0026rsquo;Art. 13 del Regolamento UE 2016/679 (GDPR).\nRoma, Marzo 2026\nScarica PDF | Profilo LinkedIn | Torna alla pagina precedente\n","date":"10 marzo 2026","permalink":"https://ivanluminaria.com/it/resumes/oracle-plsql/","section":"Know-How e Impatto","summary":"\u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://ivanluminaria.com/downloads/CV_Oracle_PLSQL_Ivan_Luminaria_202603_EN.pdf\" target=\"_blank\" rel=\"noreferrer\"\u003eScarica PDF\u003c/a\u003e\u003c/strong\u003e | \u003cstrong\u003e\u003ca href=\"https://www.linkedin.com/in/ivanluminaria\" target=\"_blank\" rel=\"noreferrer\"\u003eProfilo LinkedIn\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"profilo-professionale\" class=\"relative group\"\u003eProfilo Professionale \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#profilo-professionale\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSenior Oracle PL/SQL Developer con quasi 30 anni di esperienza nella progettazione, sviluppo, test e ottimizzazione di codice PL/SQL robusto ed efficiente per applicazioni data-intensive e sistemi di Data Warehouse. Profonda competenza nella creazione di package, procedure, funzioni, trigger e tipi complessi, con un focus costante su prestazioni, manutenibilità e qualità del codice. Esperto nell\u0026rsquo;ottimizzazione di query SQL complesse e nella gestione di grandi volumi di dati. Abile nel tradurre requisiti di business in logica applicativa performante e scalabile all\u0026rsquo;interno del database Oracle. Background consolidato anche come Oracle DBA e DWH Architect, che garantisce una visione completa del ciclo di vita del dato.\u003c/p\u003e","title":"Oracle PL/SQL Developer"},{"content":"Scarica PDF | Profilo LinkedIn\nProfilo Professionale #Project Manager con quasi 30 anni di esperienza IT e un solido background tecnico in ambienti Data Warehouse e Oracle. Oltre 10 progetti completati con consegne quasi sempre rispettate, gestendo team di 3-7 persone in contesti multiculturali e remoti su progetti con budget nell\u0026rsquo;ordine di €100K-€500K. Competenze concrete in pianificazione, gestione del rischio, coordinamento delle risorse e interfaccia con gli stakeholder — maturate sul campo coordinando attività di sviluppo, rilascio e manutenzione per clienti nei settori Banking, Telco, Assicurativo e Pubblica Amministrazione. Metodologie Agile (Scrum) applicate nella gestione quotidiana dei progetti, con formazione certificata. Background tecnico approfondito (architettura DWH, Oracle DBA, PL/SQL, ETL/ELT) che consente di parlare la stessa lingua del team di sviluppo, valutare la fattibilità delle soluzioni e identificare i rischi tecnici prima che diventino problemi.\nCompetenze Chiave # Project Management \u0026amp; Metodologie: Pianificazione di progetto, definizione delle milestone e monitoraggio dell\u0026rsquo;avanzamento. Gestione del rischio e delle criticità — identificazione proattiva e piani di mitigazione. Metodologie Agile e Scrum (Sprint Planning, Daily Stand-up, Retrospective, Backlog Refinement) — Formazione certificata. Definizione dei requisiti, gestione dello scope e interfaccia con gli stakeholder. Pianificazione dei rilasci e coordinamento delle attività di delivery. Strumenti di Project Management \u0026amp; Produttività: Microsoft Project e Jira (pianificazione, tracking, gestione backlog). Microsoft Excel e Google Sheets (reporting, dashboard di progetto, analisi dati — uso quotidiano). Git e GitHub (gestione del codice, issue tracking, CI/CD, workflow collaborativi). Competenze Tecniche a Supporto del PM: Architettura Data Warehouse (Kimball, Inmon, Google Cloud Platform). Oracle Database: DBA, Performance Tuning, PL/SQL. SQL avanzato, processi ETL/ELT, Business Intelligence. Valutazione della fattibilità tecnica e stima dell\u0026rsquo;effort di sviluppo. Leadership \u0026amp; Comunicazione: Coordinamento di team tecnici distribuiti (3-7 persone, multi-paese). Comunicazione efficace con team tecnici, stakeholder di business e management. Mentoring e sviluppo delle competenze del team. Facilitazione di meeting e gestione dei conflitti. Esperienza Professionale #IDEA DB CONSULTING S.R.L. — Roma, Italia (Full Remote Europa) #Project Manager \u0026amp; Senior DWH Architect | 2022 – Presente\nPM \u0026amp; DWH Lead (per GENERALI Assicurazioni) | Feb 2024 – Mag 2025:\nCoordinamento delle attività progettuali e gestione delle priorità per il team di sviluppo su database Oracle nel settore assicurativo. Interfaccia diretta con il cliente per la raccolta dei requisiti, la definizione dello scope e la presentazione delle soluzioni. Monitoraggio dell\u0026rsquo;avanzamento e gestione delle criticità su database da 500GB a 8TB. PM \u0026amp; DWH Lead (per ATRADIUS) | 2022 – 2026:\nGestione del progetto di consolidamento dati per la divisione Surety — coordinamento dell\u0026rsquo;integrazione dati da 4 paesi europei (Italia, Spagna, Francia, Nord Europa). Pianificazione dei rilasci e gestione del backlog di sviluppo su oltre 60.000 righe di codice PL/SQL ETL. Tracking delle attività, reporting allo stakeholder e gestione delle dipendenze tra team. Project Coordinator (Banking, Telepass e altri clienti):\nCoordinamento di progetti con riduzione dei tempi di elaborazione batch da 4 ore a meno di 30 minuti. Gestione dell\u0026rsquo;integrazione dati da oltre 15 sorgenti eterogenee su dataset superiori ai 2 miliardi di righe. Pianificazione e supervisione dei rilasci in ambienti Oracle OCI e Autonomous Database. NIMIS CONSULTING S.R.L. — Roma, Italia (Full Remote) #Senior Oracle DBA \u0026amp; Performance Tuning Expert (per TIM / HUAWEI) | 2020 – 2022\nPianificazione ed esecuzione di attività di manutenzione e patching su oltre 30 database Oracle critici (70+ istanze) su cluster Exadata. Coordinamento con il team di sviluppo per ottimizzare le interazioni con il database e risolvere problemi di prestazioni — supporto tecnico specializzato e prioritizzazione degli interventi. Gestione autonoma del proprio carico di lavoro e delle attività di tuning, con reportistica verso il responsabile di progetto. LIBERO PROFESSIONISTA / CONSULENTE INDIPENDENTE — Roma, Italia (Full Remote Europa) #Project Manager \u0026amp; Senior DWH Consultant | 2013 – 2020\nGestione di circa 10 progetti in 7 anni per clienti nei settori Banking, Telco e servizi, con budget nell\u0026rsquo;ordine di €100K-€500K e consegne quasi sempre rispettate. Coordinamento di team di 3-7 persone in contesti multiculturali e distribuiti — assegnazione dei compiti, facilitazione della collaborazione e gestione delle priorità con approccio iterativo Agile. Interfaccia diretta con i clienti per la raccolta dei requisiti, la definizione dello scope, la presentazione degli avanzamenti e la gestione delle aspettative. Formazione tecnica e mentoring per i membri del team — sviluppo delle competenze e onboarding dei nuovi consulenti. AUSELDA AED GROUP S.P.A. — Roma, Italia #Senior Data Warehouse Specialist \u0026amp; Oracle DBA (per la Pubblica Amministrazione) | 2009 – 2013\nCollaborazione con i referenti di progetto per la definizione dei requisiti tecnici, la pianificazione delle attività e la validazione delle soluzioni. Coordinamento delle attività di sviluppo e ottimizzazione dei Data Warehouse per enti della Pubblica Amministrazione. Supporto tecnico e formazione utenti sulle piattaforme DWH. ORACLE ITALIA S.R.L. — Varie sedi, Italia \u0026amp; Madrid, Spagna #Senior Consultant / DWH Specialist / Training Specialist | 1999 – 2009\nPartecipazione a progetti complessi di implementazione DWH e BI per clienti primari (Telco, Finance, Farmaceutico), con responsabilità crescenti nel coordinamento delle attività e nel supporto ai consulenti junior. Gestione delle relazioni con i referenti tecnici del cliente e reportistica sull\u0026rsquo;avanzamento delle attività. Come Training Specialist (2000-2001): Erogazione di corsi tecnici Oracle, gestione dell\u0026rsquo;aula e adattamento dei contenuti — competenze di presentazione e formazione applicabili al ruolo di PM. Formazione # Facoltà di Ingegneria Informatica (Ingegneria del Software) | Università degli Studi Roma Tre, Roma | 1994 – 2000 Diploma di Maturità Scientifica (EQF Livello 4) | Liceo Scientifico Isacco Newton / Manieri Copernico, Roma | 1988 – 1993 Inglese Avanzato (C1/C2) | The British Council (Livello 4A), Roma | 2003 – 2004 Corsi di Formazione e Aggiornamento Selezionati:\nProject Management — Randstad/Forma.temp (Maggio 2024) Scrum Agile — Randstad/Forma.temp (Maggio 2024) Data Wrangling, Analysis and AB Testing with SQL — Coursera, University of California Davis (Aprile 2021) Data Science on Google Cloud Platform: Designing Data Warehouses — LinkedIn Learning (Settembre 2020) Corsi di specializzazione Oracle 12c (Administration, Security, Backup and Recovery, Advanced SQL, Performance Optimization) — LinkedIn Learning (2020) Learning Excel 2016 — LinkedIn Learning (Agosto 2020) Learning Git and GitHub — LinkedIn Learning (Agosto 2020) Lingue # Italiano: Madrelingua Inglese: C1/C2 (Fluente, professionale) Spagnolo: C1 (Fluente) Rumeno: C1 (Fluente) Francese: A1/A2 (Base) Competenze Trasversali # Capacità di tradurre requisiti tecnici in piani di progetto concreti e gestibili Gestione simultanea di più progetti con priorità concorrenti Comunicazione efficace a tutti i livelli (team tecnico, stakeholder, management) Problem Solving analitico e gestione proattiva dei rischi Esperienza di lavoro in team distribuiti, multiculturali e full-remote Mentoring e sviluppo delle competenze del team Autorizzo il trattamento dei miei dati personali ai sensi dell\u0026rsquo;Art. 13 del Regolamento UE 2016/679 (GDPR).\nRoma, Marzo 2026\nScarica PDF | Profilo LinkedIn | Torna alla pagina precedente\n","date":"10 marzo 2026","permalink":"https://ivanluminaria.com/it/resumes/project-manager/","section":"Know-How e Impatto","summary":"\u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://ivanluminaria.com/downloads/CV_Project_Manager_Ivan_Luminaria_202603_EN.pdf\" target=\"_blank\" rel=\"noreferrer\"\u003eScarica PDF\u003c/a\u003e\u003c/strong\u003e | \u003cstrong\u003e\u003ca href=\"https://www.linkedin.com/in/ivanluminaria\" target=\"_blank\" rel=\"noreferrer\"\u003eProfilo LinkedIn\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"profilo-professionale\" class=\"relative group\"\u003eProfilo Professionale \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#profilo-professionale\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eProject Manager con quasi 30 anni di esperienza IT e un solido background tecnico in ambienti Data Warehouse e Oracle. Oltre 10 progetti completati con consegne quasi sempre rispettate, gestendo team di 3-7 persone in contesti multiculturali e remoti su progetti con budget nell\u0026rsquo;ordine di €100K-€500K. Competenze concrete in pianificazione, gestione del rischio, coordinamento delle risorse e interfaccia con gli stakeholder — maturate sul campo coordinando attività di sviluppo, rilascio e manutenzione per clienti nei settori Banking, Telco, Assicurativo e Pubblica Amministrazione. Metodologie Agile (Scrum) applicate nella gestione quotidiana dei progetti, con formazione certificata. Background tecnico approfondito (architettura DWH, Oracle DBA, PL/SQL, ETL/ELT) che consente di parlare la stessa lingua del team di sviluppo, valutare la fattibilità delle soluzioni e identificare i rischi tecnici prima che diventino problemi.\u003c/p\u003e","title":"Project Manager"},{"content":"Lunedì mattina. Sveglia alle 6:40. Doccia, colazione veloce, chiavi della macchina sul tavolo. Esco di casa alle 7:15.\nAbito in zona Appio Latino. L\u0026rsquo;ufficio è in Via Crescenzio, a Prati. Otto chilometri in linea d\u0026rsquo;aria. Dovrebbero essere quindici minuti. A Roma, sono un\u0026rsquo;altra cosa.\n🚗 La mattina in macchina #Via Appia Nuova è già un parcheggio. Porta San Giovanni, un imbuto. Lungotevere, una processione funebre con i clacson.\nCinquanta minuti per fare otto chilometri. Cinquanta minuti di frizione, semafori, doppia fila, motorini che ti tagliano la strada e autobus che si fermano in seconda corsia.\nMa il bello deve ancora venire.\nArrivo a Prati e comincia la caccia al parcheggio. Via Crescenzio, piena. Via Tacito, piena. Le traverse, piene. Giro a vuoto per un\u0026rsquo;ora e mezza. Un\u0026rsquo;ora e mezza. A camminare a passo d\u0026rsquo;uomo tra le strade di Prati, con il motore acceso e la pazienza che scende sotto zero.\nAlla fine, sfinito, alzo bandiera bianca. Parcheggio multipiano di Piazza Cavour. \u0026ldquo;Almeno qui trovo posto\u0026rdquo;, penso.\nTrovo posto. Trovo anche il conto: la sera, quando esco, lo scontrino dice 35 euro.\nTrentacinque euro per il privilegio di aver lasciato la macchina ferma tutto il giorno.\nFacciamo il bilancio di quella mattina:\nVoce Valore Orario di uscita da casa 7:15 Tempo in auto nel traffico 50 minuti Tempo a cercare parcheggio 1 ora e 30 minuti Orario di arrivo alla scrivania 9:35 Costo parcheggio 35€ Livello di stress ████████████ 200% Produttività della prima ora vicina allo zero Due ore e venti minuti. Per fare otto chilometri. E 35 euro in meno nel portafoglio.\nQuella sera torno a casa e penso: \u0026ldquo;Ci deve essere un altro modo.\u0026rdquo;\n🚲 La settimana dopo: la Brompton elettrica #Il lunedì successivo cambio tutto.\nEsco di casa alle 7:30 — quindici minuti dopo rispetto alla settimana prima. Scendo con la mia Brompton elettrica. La apro in dieci secondi sul marciapiede. Casco, zaino, via.\nStessa strada. Appio Latino → San Giovanni → Celio → Lungotevere → Prati.\nMa stavolta è tutto diverso.\nMentre le auto sono ferme in colonna, io passo. Mentre i motorini fanno lo slalom tra i paraurti, io pedalo tranquillo nella corsia ciclabile. Non sudo — è una bici elettrica, l\u0026rsquo;assistenza fa il suo lavoro. Non mi stresso — non ho nessuno che mi suona il clacson. Non cerco parcheggio — la Brompton la ripiego e me la porto su in ufficio.\nDiciotto minuti. Porta a porta.\nVoce Valore Orario di uscita da casa 7:30 Tempo in bici 18 minuti Tempo a cercare parcheggio 0 minuti Orario di arrivo alla scrivania 7:50 Costo 0€ Livello di stress ░░░░░░░░░░░░ 0% Produttività della prima ora massima Alle 7:50 ero seduto alla scrivania. Fresco. Sveglio. Con il caffè in mano e la testa già sul primo task della giornata.\nUn\u0026rsquo;ora e quarantacinque minuti prima rispetto alla settimana precedente.\nTrentacinque euro risparmiati.\nE soprattutto: zero stress.\n📊 I numeri su un anno intero #Facciamo i conti seri. Su 220 giorni lavorativi:\n🚗 Auto 🚲 Brompton Tempo medio porta-a-porta (andata) 50 min + 30 min parcheggio 18 min Tempo giornaliero (A/R) ~2h 40min ~36 min Tempo annuo in viaggio ~587 ore ~132 ore Ore risparmiate con la bici ~455 ore Costo carburante annuo ~1.800€ 0€ Parcheggio/ZTL/multe ~1.200€ (stima conservativa) 0€ Assicurazione + bollo + usura ~2.500€ 0€ Costo annuo mobilità ~5.500€ ~50€ (manutenzione) Risparmio annuo ~5.450€ 455 ore risparmiate. Sono 57 giornate lavorative. Due mesi e mezzo di vita restituiti.\nE quei 5.450 euro risparmiati? Sono una vacanza. Sono un fondo pensione. Sono il costo della Brompton stessa, ripagata in meno di un anno.\n💪 I benefici che non si misurano in euro #Ma i numeri economici sono solo una parte della storia. Quelli che contano davvero sono gli altri.\nSalute cardiovascolare #Pedalare 36 minuti al giorno, anche con pedalata assistita, è attività fisica moderata. L\u0026rsquo;Organizzazione Mondiale della Sanità raccomanda almeno 150 minuti di attività aerobica a settimana. Con la bici per andare al lavoro, ne fai 180 senza nemmeno pensarci.\nStudi pubblicati sul British Medical Journal dimostrano che chi va al lavoro in bici ha:\n41% in meno di rischio di morte per tutte le cause 52% in meno di rischio di morte per malattie cardiovascolari 45% in meno di rischio di sviluppare tumori Non sono numeri miei. Sono numeri della scienza, su un campione di oltre 250.000 pendolari britannici seguiti per cinque anni.\nSalute mentale #Il traffico di Roma non è solo noioso. È tossico per la mente. Lo stress cronico da pendolarismo è correlato a:\naumento dei livelli di cortisolo disturbi del sonno maggiore irritabilità e ansia riduzione della capacità di concentrazione Pedalare, al contrario, rilascia endorfine. Arrivi al lavoro con la testa ossigenata, l\u0026rsquo;umore alto e un senso di autonomia che il sedile di un\u0026rsquo;auto nel traffico non ti darà mai.\nQualità dell\u0026rsquo;aria #Un\u0026rsquo;auto ferma nel traffico di Roma produce in media 120-150 g di CO₂ per chilometro. Nel traffico congestionato, anche di più — perché il motore gira al minimo, consumando senza muoversi.\nUna bici produce zero emissioni.\nSe solo il 10% dei pendolari romani passasse all\u0026rsquo;uso quotidiano della bici, si risparmierebbero circa 150.000 tonnellate di CO₂ all\u0026rsquo;anno. È l\u0026rsquo;equivalente di piantare 7 milioni di alberi.\nNon è idealismo. È aritmetica.\n🤔 \u0026ldquo;Ma piove, fa caldo, è pericoloso\u0026hellip;\u0026rdquo; #Lo so. Le obiezioni le conosco tutte. Me le sono fatte anch\u0026rsquo;io.\n\u0026ldquo;E quando piove?\u0026rdquo;\nPiove circa 75 giorni all\u0026rsquo;anno a Roma. Nei giorni di pioggia forte, prendo la metro da San Giovanni a Lepanto. Quindici minuti. Niente auto nemmeno sotto il diluvio. La Brompton si piega e sale in metro con me.\n\u0026ldquo;D\u0026rsquo;estate fa troppo caldo.\u0026rdquo;\nCon la pedalata assistita non sudi. E anche se sudassi leggermente, meglio 18 minuti di aria aperta che 50 minuti in un abitacolo rovente con l\u0026rsquo;aria condizionata che ti secca la gola.\n\u0026ldquo;Le strade di Roma non sono sicure.\u0026rdquo;\nQuesto è vero, e non lo minimizzo. Roma ha bisogno di più infrastrutture ciclabili. Ma il mio percorso — Appio Latino, Celio, Lungotevere — è ragionevolmente sicuro, soprattutto nelle ore di punta quando il traffico è così lento che le auto vanno più piano della bici.\n\u0026ldquo;Non posso portare la bici in ufficio.\u0026rdquo;\nLa Brompton si piega in 20 secondi e diventa un bagaglio da mettere sotto la scrivania. È questo il suo superpotere: elimina completamente il problema del parcheggio.\n🌍 Non è solo una scelta personale #Ogni persona che lascia l\u0026rsquo;auto a casa e prende la bici:\nlibera un posto auto per chi ne ha davvero bisogno riduce il traffico per chi deve per forza guidare migliora la qualità dell\u0026rsquo;aria per tutti riduce l\u0026rsquo;inquinamento acustico del quartiere dimostra che un altro modello è possibile Non sto chiedendo a nessuno di vendere la macchina. Sto dicendo che per molti tragitti urbani — quelli sotto i 10 km — la bici è oggettivamente superiore all\u0026rsquo;auto. Più veloce, più economica, più sana, più sostenibile.\nE con una pieghevole elettrica, le ultime scuse cadono una dopo l\u0026rsquo;altra.\n🇪🇺 In Europa lo fanno già — e funziona #Mentre a Roma discutiamo se sia possibile andare al lavoro in bici, in mezza Europa lo fanno già da decenni.\nAmsterdam ha più biciclette che abitanti — 881.000 bici per 872.000 residenti. Il problema non è convincere la gente a pedalare, ma dove parcheggiare tutte quelle bici. Alla Stazione Centrale hanno costruito il più grande parcheggio per biciclette del mondo: 12.500 posti su tre piani sotterranei. Dodicimilacinquecento. Non posti auto. Posti bici.\nCopenhagen ha raggiunto il traguardo storico: più del 60% dei residenti va al lavoro in bici. Non per ideologia, ma per praticità. Il tragitto medio dura 13 minuti. Provate a fare lo stesso in macchina.\nMonaco di Baviera, Berlino, Vienna — città con inverni ben più rigidi di Roma — hanno reti ciclabili capillari e percentuali di ciclisti urbani che a Roma ci sogniamo.\nE non serve guardare oltre le Alpi. Milano, Bologna, Ferrara, Padova — nel nord Italia pedalare per andare al lavoro è normale. Non è eroismo. Non è eccentricità. È buon senso.\nI sette colli? Con l\u0026rsquo;elettrica non sono più una scusa #Lo so cosa state pensando. \u0026ldquo;Sì, ma quelle sono città piatte. Roma ha i sette colli.\u0026rdquo;\nÈ vero. Roma ha salite. Il Celio, l\u0026rsquo;Aventino, il Gianicolo — non sono esattamente pianura padana.\nMa questa obiezione aveva senso dieci anni fa. Oggi, con una bici elettrica, i sette colli non esistono più. Il motore ti assiste in salita, arrivi in cima senza fiatone, senza sudore, senza rimpiangere la macchina.\nLa mia Brompton elettrica affronta la salita del Celio come se fosse un leggero dosso. Il Lungotevere è pianeggiante. E il tratto finale verso Prati è in discesa.\nRoma ha 300 giorni di sole all\u0026rsquo;anno, un clima mite anche d\u0026rsquo;inverno, e distanze urbane contenute. È — paradossalmente — una delle città italiane più adatte alla bicicletta. Ci mancano solo le infrastrutture. E il coraggio di cambiare abitudini.\n🏠 Bici e smart working: la combinazione perfetta #C\u0026rsquo;è un legame profondo tra la scelta della bici e la filosofia dello smart working. Entrambi partono dalla stessa domanda: \u0026ldquo;Ha senso quello che sto facendo, o lo faccio solo perché si è sempre fatto così?\u0026rdquo;\nLo smart working elimina il pendolarismo nei giorni in cui non serve essere in ufficio. La bici rende il pendolarismo intelligente nei giorni in cui serve esserci.\nIl modello ideale? 3 giorni da remoto, 2 in ufficio — in bicicletta.\nModello Ore settimanali in viaggio Stress Costo 5 giorni auto ~13 ore alto ~110€/settimana 5 giorni auto + smart working (3+2) ~5 ore medio ~44€/settimana 2 giorni bici + 3 smart working ~1,2 ore zero ~0€ Da 13 ore a 1 ora e 12 minuti. Da 110 euro a zero.\nNon è utopia. È organizzazione.\nNon è pigrizia. È intelligenza.\nSe le aziende combinassero smart working e incentivi alla mobilità sostenibile, il risultato sarebbe triplo: dipendenti più sani, più produttivi e città più vivibili. Ma per arrivarci, serve smettere di pensare che \u0026ldquo;lavorare\u0026rdquo; significhi \u0026ldquo;stare seduti in un ufficio dalle 9 alle 18 dopo un\u0026rsquo;ora di macchina.\u0026rdquo;\n🎯 Il mio bilancio personale #Da quando ho fatto il cambio, la mia mattina è questa:\nOra Attività 7:00 Sveglia 7:00 — 7:25 Colazione con calma, notizie 7:30 Uscita di casa in Brompton 7:48 Arrivo in ufficio, bici ripiegata sotto la scrivania 7:50 Operativo Niente stress. Niente costi. Niente sorprese da 35 euro.\nE la sera, stessa cosa al contrario: 18 minuti e sono a casa. Non un\u0026rsquo;ora. Non \u0026ldquo;dipende dal traffico\u0026rdquo;. Diciotto minuti, sempre.\nHo recuperato tempo. Ho recuperato soldi. Ho recuperato energia mentale.\nMa soprattutto, ho recuperato il piacere di muovermi per la città invece di subirla.\n💬 A chi è ancora fermo nel traffico #Se ogni mattina passi un\u0026rsquo;ora in macchina per fare un tragitto che in bici faresti in venti minuti.\nSe ogni sera torni a casa svuotato, non dal lavoro, ma dal viaggio per arrivarci.\nSe hai mai calcolato quanto spendi in benzina, parcheggio e sanità mentale.\nProva. Anche solo per una settimana.\nPrendi una bici — pieghevole, elettrica, quella che preferisci — e fai lo stesso percorso.\nGuarda l\u0026rsquo;orologio quando arrivi. Guarda come ti senti. Guarda il portafoglio a fine mese.\nI numeri parlano da soli.\nMa il sorriso con cui arrivi alla scrivania, quello, non ha prezzo.\nGlossario #Brompton — Bicicletta pieghevole britannica considerata il riferimento mondiale per qualità costruttiva, compattezza da piegata e praticità nel pendolarismo urbano.\nPedalata Assistita — Sistema di propulsione elettrica che amplifica la forza della pedalata, eliminando il problema delle salite e del sudore nei tragitti urbani.\nBicicletta Pieghevole — Bicicletta che si ripiega in 10-20 secondi diventando un bagaglio trasportabile in ufficio, in metro o in treno.\nPendolarismo — Spostamento quotidiano casa-lavoro e ritorno, che nelle grandi città può assorbire 2-4 ore al giorno e centinaia di euro al mese.\nCarbon Footprint — Quantità totale di gas serra emessi da un\u0026rsquo;attività — un\u0026rsquo;auto nel traffico romano produce 120-150 g di CO₂ per chilometro, una bici zero.\nMobilità Sostenibile — Approccio ai trasporti urbani che privilegia mezzi a basso impatto ambientale, riducendo emissioni, traffico e costi.\n","date":"3 marzo 2026","permalink":"https://ivanluminaria.com/it/posts/project-management/bici-vs-auto-roma/","section":"Database Strategy","summary":"\u003cp\u003eLunedì mattina. Sveglia alle 6:40. Doccia, colazione veloce, chiavi della macchina sul tavolo. Esco di casa alle 7:15.\u003c/p\u003e\n\u003cp\u003eAbito in zona Appio Latino. L\u0026rsquo;ufficio è in Via Crescenzio, a Prati. Otto chilometri in linea d\u0026rsquo;aria. Dovrebbero essere quindici minuti. A Roma, sono un\u0026rsquo;altra cosa.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"-la-mattina-in-macchina\" class=\"relative group\"\u003e🚗 La mattina in macchina \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-la-mattina-in-macchina\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eVia Appia Nuova è già un parcheggio. Porta San Giovanni, un imbuto. Lungotevere, una processione funebre con i clacson.\u003c/p\u003e","title":"Bici vs Auto a Roma: la mattina che mi ha aperto gli occhi"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/cycling/","section":"Tags","summary":"","title":"Cycling"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/health/","section":"Tags","summary":"","title":"Health"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/smart-working/","section":"Tags","summary":"","title":"Smart-Working"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/sustainability/","section":"Tags","summary":"","title":"Sustainability"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/urban-mobility/","section":"Tags","summary":"","title":"Urban-Mobility"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/hugepages/","section":"Tags","summary":"","title":"Hugepages"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/kernel/","section":"Tags","summary":"","title":"Kernel"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/linux/","section":"Tags","summary":"","title":"Linux"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/categories/oracle/","section":"Categories","summary":"","title":"Oracle"},{"content":"Il cliente era una società di logistica con un Oracle 19c Enterprise Edition su Oracle Linux 8. Sessanta utenti concorrenti, un gestionale custom, circa 400 GB di dati. Il server era un Dell PowerEdge con 128 GB di RAM e 32 core.\nLe lamentele erano vaghe ma persistenti: \u0026ldquo;Il sistema è lento.\u0026rdquo; \u0026ldquo;Le query del mattino ci mettono il doppio rispetto a due mesi fa.\u0026rdquo; \u0026ldquo;Ogni tanto si blocca tutto per qualche secondo.\u0026rdquo;\nQuando sono entrato sul server, la prima cosa che ho verificato non è stata il database. È stato il sistema operativo.\ncat /proc/meminfo | grep -i huge sysctl vm.nr_hugepages cat /sys/kernel/mm/transparent_hugepage/enabled Risultato: zero Huge Pages configurate, Transparent Huge Pages attive, parametri kernel tutti ai valori di default. L\u0026rsquo;installazione di Oracle era stata fatta col wizard, il sistema operativo non era stato toccato.\nEcco il problema. Non era Oracle. Era Linux che non era stato preparato per Oracle.\n🔍 La diagnosi #Prima di cambiare qualsiasi cosa, ho misurato lo stato attuale. Servono numeri, non impressioni.\n# Stato della SGA sqlplus -s / as sysdba \u0026lt;\u0026lt;SQL SELECT name, value/1024/1024 AS mb FROM v$sgainfo WHERE name IN (\u0026#39;Maximum SGA Size\u0026#39;, \u0026#39;Free SGA Memory Available\u0026#39;); SQL # Utilizzo memoria del sistema free -h # Parametri kernel correnti sysctl -a | grep -E \u0026#34;kernel.sem|kernel.shm|vm.nr_hugepages|vm.swappiness\u0026#34; # I/O scheduler in uso cat /sys/block/sda/queue/scheduler # Limiti utente oracle su - oracle -c \u0026#34;ulimit -a\u0026#34; Ecco cosa ho trovato:\nParametro Valore attuale Valore raccomandato SGA Target 64 GB 64 GB (ok) vm.nr_hugepages 0 33280 Transparent Huge Pages always never vm.swappiness 60 1 kernel.shmmax 33554432 (32 MB) 68719476736 (64 GB) kernel.shmall 2097152 16777216 kernel.sem 250 32000 100 128 250 32000 100 256 I/O scheduler mq-deadline deadline (ok) oracle nofile 1024 65536 oracle nproc 4096 16384 oracle memlock 65536 KB unlimited Quasi tutto era sbagliato. Non per errore — per omissione. Nessuno si era preso la briga di configurare il sistema operativo dopo l\u0026rsquo;installazione.\n📦 Huge Pages: il parametro che cambia tutto #Le Huge Pages sono il singolo parametro più impattante per Oracle su Linux. E sono anche quello che viene ignorato più spesso.\nPerché servono #Di default, Linux gestisce la memoria in pagine da 4 KB. Un\u0026rsquo;SGA da 64 GB significa circa 16,7 milioni di pagine. Ogni pagina ha una entry nella Page Table, e il sistema deve tradurre indirizzi virtuali in fisici per ciascuna. Il TLB (Translation Lookaside Buffer) della CPU può memorizzare solo poche migliaia di traduzioni — il resto viene gestito dalla MMU, che è lenta.\nLe Huge Pages sono pagine da 2 MB. La stessa SGA da 64 GB diventa 32.768 pagine. Il TLB regge, la pressione sulla MMU crolla, le performance migliorano.\nCome configurarle #Ho calcolato il numero di Huge Pages necessarie:\n# SGA = 64 GB = 65536 MB # Ogni Huge Page = 2 MB # Pagine necessarie = 65536 / 2 = 32768 # Aggiungo un 1.5% di margine → 33280 echo \u0026#34;vm.nr_hugepages = 33280\u0026#34; \u0026gt;\u0026gt; /etc/sysctl.d/99-oracle.conf sysctl -p /etc/sysctl.d/99-oracle.conf Verifica:\ngrep -i huge /proc/meminfo Output atteso:\nHugePages_Total: 33280 HugePages_Free: 33280 HugePages_Rsvd: 0 Hugepagesize: 2048 kB Dopo il riavvio dell\u0026rsquo;istanza Oracle, la SGA viene allocata nelle Huge Pages:\nHugePages_Total: 33280 HugePages_Free: 512 HugePages_Rsvd: 480 La differenza è misurabile: le latch free wait e i library cache contention si riducono drasticamente.\n🧱 Shared memory e semafori #Oracle usa la shared memory del kernel per la SGA. Se i limiti sono troppo bassi, l\u0026rsquo;istanza non riesce ad allocare la memoria richiesta — o peggio, frammenta l\u0026rsquo;allocazione.\ncat \u0026gt;\u0026gt; /etc/sysctl.d/99-oracle.conf \u0026lt;\u0026lt; \u0026#39;SYSCTL\u0026#39; # Shared memory kernel.shmmax = 68719476736 kernel.shmall = 16777216 kernel.shmmni = 4096 # Semaphores: SEMMSL SEMMNS SEMOPM SEMMNI kernel.sem = 250 32000 100 256 SYSCTL sysctl -p /etc/sysctl.d/99-oracle.conf Parametro Significato Valore shmmax Dimensione massima di un singolo segmento di shared memory 64 GB shmall Pagine totali di shared memory allocabili 64 GB in pagine da 4K shmmni Numero massimo di segmenti di shared memory 4096 sem SEMMSL, SEMMNS, SEMOPM, SEMMNI 250 32000 100 256 Queste impostazioni non sono valori magici. Sono dimensionate sulla SGA del database. Se l\u0026rsquo;SGA cambia, i parametri vanno ricalcolati.\n💾 I/O Scheduler #Il default su RHEL/Oracle Linux 8 con device NVMe è none o mq-deadline. Per i dischi SAS/SATA tradizionali, il default potrebbe essere bfq o cfq.\nPer Oracle, la raccomandazione è deadline (o mq-deadline sui kernel più recenti):\n# Verifica corrente cat /sys/block/sda/queue/scheduler # Se non è deadline/mq-deadline, impostarlo echo \u0026#34;deadline\u0026#34; \u0026gt; /sys/block/sda/queue/scheduler # Per renderlo permanente via GRUB grubby --update-kernel=ALL --args=\u0026#34;elevator=deadline\u0026#34; cfq (Completely Fair Queuing) è pensato per workload desktop — distribuisce equamente l\u0026rsquo;I/O tra i processi. Ma Oracle non ha bisogno di equità: ha bisogno che le richieste I/O vengano servite nell\u0026rsquo;ordine che minimizza i seek. deadline fa esattamente questo.\n🚫 Disabilitare Transparent Huge Pages #Questo è il parametro più insidioso. Le Transparent Huge Pages (THP) sono una funzione del kernel che sembra una buona idea: il kernel promuove automaticamente le pagine normali a pagine grandi.\nPer Oracle è un disastro. Il processo khugepaged lavora in background per compattare le pagine, causando latenze imprevedibili — quei \u0026ldquo;blocchi di qualche secondo\u0026rdquo; che il cliente lamentava.\nOracle lo dice esplicitamente nella documentazione: disabilitare THP.\n# Verifica stato corrente cat /sys/kernel/mm/transparent_hugepage/enabled # Output tipico: [always] madvise never # Disabilitare a runtime echo never \u0026gt; /sys/kernel/mm/transparent_hugepage/enabled echo never \u0026gt; /sys/kernel/mm/transparent_hugepage/defrag # Renderlo permanente via GRUB grubby --update-kernel=ALL --args=\u0026#34;transparent_hugepage=never\u0026#34; Dopo il reboot, verificare:\ncat /sys/kernel/mm/transparent_hugepage/enabled # Output atteso: always madvise [never] La differenza è netta: i micro-freeze random scompaiono.\n🔒 Security limits #L\u0026rsquo;utente oracle ha bisogno di limiti elevati su file descriptor aperti, processi e memoria bloccabile. I default di Linux sono pensati per utenti interattivi, non per un software che gestisce centinaia di connessioni simultanee.\ncat \u0026gt;\u0026gt; /etc/security/limits.d/99-oracle.conf \u0026lt;\u0026lt; \u0026#39;LIMITS\u0026#39; oracle soft nofile 65536 oracle hard nofile 65536 oracle soft nproc 16384 oracle hard nproc 16384 oracle soft stack 10240 oracle hard stack 32768 oracle soft memlock unlimited oracle hard memlock unlimited LIMITS Limite Default Raccomandato Perché nofile 1024 65536 Oracle apre un file descriptor per ogni datafile, redo log, archive log nproc 4096 16384 Ogni processo Oracle è un processo OS separato memlock 65536 KB unlimited Necessario per il lock della SGA in Huge Pages stack 8192 KB 10240-32768 KB PL/SQL ricorsivo profondo può esaurire lo stack Il memlock unlimited è fondamentale: senza di esso, Oracle non può bloccare la SGA nelle Huge Pages, rendendo inutile la configurazione fatta prima.\n⚡ Swappiness #Il valore di default di vm.swappiness è 60. Significa che Linux inizia a swappare quando la pressione sulla memoria è ancora bassa. Per un server database dedicato, questo è inaccettabile: vuoi che la SGA resti in RAM, sempre.\necho \u0026#34;vm.swappiness = 1\u0026#34; \u0026gt;\u0026gt; /etc/sysctl.d/99-oracle.conf sysctl -p /etc/sysctl.d/99-oracle.conf Non zero — uno. Il valore zero disabilita completamente lo swap, il che può causare OOM killer in situazioni di pressione estrema. Il valore uno dice al kernel: \u0026ldquo;Swappa solo se non c\u0026rsquo;è davvero più alternativa.\u0026rdquo;\n📊 Prima e dopo #Dopo aver applicato tutte le configurazioni e riavviato l\u0026rsquo;istanza Oracle, ho rifatto le misurazioni.\nMetrica Prima Dopo Variazione SGA in Huge Pages No Sì — Library cache hit ratio 92,3% 99,7% +7,4% Buffer cache hit ratio 94,1% 99,2% +5,1% Average wait time (db file sequential read) 8,2 ms 1,4 ms -83% Micro-freeze random (\u0026gt;1s) 5-8 al giorno 0 -100% Tempo medio batch mattutino 47 min 22 min -53% CPU utilization media 78% 41% -47% Swap utilizzato 3,2 GB 0 MB -100% I numeri parlano da soli. La stessa macchina, lo stesso database, lo stesso carico di lavoro. L\u0026rsquo;unica differenza: il sistema operativo è stato configurato per fare il suo lavoro.\n📋 Checklist finale #Per chi vuole un riepilogo operativo, ecco la checklist completa:\n# /etc/sysctl.d/99-oracle.conf vm.nr_hugepages = 33280 vm.swappiness = 1 kernel.shmmax = 68719476736 kernel.shmall = 16777216 kernel.shmmni = 4096 kernel.sem = 250 32000 100 256 # /etc/security/limits.d/99-oracle.conf oracle soft nofile 65536 oracle hard nofile 65536 oracle soft nproc 16384 oracle hard nproc 16384 oracle soft stack 10240 oracle hard stack 32768 oracle soft memlock unlimited oracle hard memlock unlimited # GRUB grubby --update-kernel=ALL --args=\u0026#34;transparent_hugepage=never elevator=deadline\u0026#34; Dieci minuti di configurazione. Nessun costo hardware. Nessuna licenza aggiuntiva.\nMa nessuno lo fa, perché il wizard non lo chiede, la documentazione è sepolta in una nota MOS, e il sistema \u0026ldquo;funziona anche senza.\u0026rdquo; Funziona. Male. E la colpa ricade sempre su Oracle, mai sul fatto che nessuno ha preparato il terreno.\nUn database è buono quanto il sistema operativo su cui gira. E un sistema operativo lasciato ai default è un sistema operativo che lavora contro di te.\nGlossario #Huge Pages — Pagine di memoria da 2 MB (invece dei 4 KB standard) che riducono drasticamente la pressione sulla MMU e sul TLB, migliorando le performance di Oracle su Linux.\nTHP — Transparent Huge Pages — funzione del kernel Linux che promuove automaticamente le pagine normali a pagine grandi, ma che causa latenze imprevedibili e deve essere disabilitata per Oracle.\nSGA — System Global Area — area di memoria condivisa di Oracle Database che contiene buffer cache, shared pool, redo log buffer e altre strutture critiche per le performance.\nI/O Scheduler — Componente del kernel Linux che decide l\u0026rsquo;ordine in cui le richieste di I/O vengono inviate al disco, con impatto diretto sulle performance del database.\nSwappiness — Parametro kernel Linux (vm.swappiness) che controlla la propensione del sistema a spostare pagine di memoria nello swap, critico per i server database.\n","date":"24 febbraio 2026","permalink":"https://ivanluminaria.com/it/posts/oracle/oracle-linux-kernel/","section":"Database Strategy","summary":"\u003cp\u003eIl cliente era una società di logistica con un Oracle 19c Enterprise Edition su Oracle Linux 8. Sessanta utenti concorrenti, un gestionale custom, circa 400 GB di dati. Il server era un Dell PowerEdge con 128 GB di RAM e 32 core.\u003c/p\u003e\n\u003cp\u003eLe lamentele erano vaghe ma persistenti: \u0026ldquo;Il sistema è lento.\u0026rdquo; \u0026ldquo;Le query del mattino ci mettono il doppio rispetto a due mesi fa.\u0026rdquo; \u0026ldquo;Ogni tanto si blocca tutto per qualche secondo.\u0026rdquo;\u003c/p\u003e","title":"Oracle su Linux: i parametri kernel che nessuno configura"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/productivity/","section":"Tags","summary":"","title":"Productivity"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/remote-work/","section":"Tags","summary":"","title":"Remote-Work"},{"content":"Ore 6:47 di un martedì qualunque. Sono al parco sotto casa, in tenuta da corsa. L\u0026rsquo;aria è fresca, il sole sta appena salendo. Ho già fatto quattro chilometri. Mi sento vivo.\nAlle 7:00 sono sotto la doccia. Alle 7:20 faccio colazione con calma. Alle 7:45 sono alla scrivania, fresco, concentrato, pronto a lavorare.\nA quell\u0026rsquo;ora, un mio collega è ancora fermo sulla Pontina. O sul raccordo, tra Casilina e Tuscolana. Ha già il telefono in mano — non per lavorare, ma per mandare il classico messaggio: \u0026ldquo;Scusa, arrivo tardi, c\u0026rsquo;è un incidente.\u0026rdquo;\nDue persone. Stesso lavoro. Stesso contratto.\nUno è già produttivo. L\u0026rsquo;altro sta bruciando le sue migliori energie in un abitacolo.\nQuesta non è un\u0026rsquo;opinione. Questi sono fatti.\nE i fatti hanno dei numeri.\n🚗 Il costo invisibile del pendolarismo a Roma #Parliamoci chiaro: Roma non è una città. È un organismo caotico che si muove a singhiozzo.\nPer chi lavora in consulenza IT e vive fuori dal centro — e a Roma \u0026ldquo;fuori dal centro\u0026rdquo; vuol dire praticamente ovunque — il tragitto casa-ufficio è un\u0026rsquo;impresa quotidiana.\nFacciamo due conti su uno scenario reale:\nVoce Valore Distanza casa-ufficio ~30 km (un quarto di raccordo) Tempo medio andata 1h 15min — 2h 30min Tempo medio ritorno 1h — 1h 45min Tempo totale giornaliero in auto 2h 15min — 4h 15min Giorni lavorativi al mese 21 Ore perse al mese in auto 47 — 89 ore Costo carburante mensile (~30km x 2 x 21gg) ~250-300€ Usura auto, assicurazione, parcheggio ~150-200€/mese Costo totale mensile pendolarismo ~400-500€ Quasi 90 ore al mese nel caso peggiore. Sono più di due settimane lavorative passate in macchina. Non a lavorare. Non a pensare. A imprecare contro il traffico.\nE non ho ancora contato lo stress. La frustrazione. L\u0026rsquo;energia mentale che si brucia prima ancora di accendere il computer.\n🏃 L\u0026rsquo;altra faccia della medaglia: la mattina di chi lavora da casa #Ecco la mia giornata tipo:\nOra Attività 6:00 Sveglia 6:10 — 6:45 Corsa al parco (4-5 km) 6:50 — 7:10 Doccia 7:10 — 7:30 Colazione con calma 7:30 — 7:45 Setup postazione, caffè, revisione agenda 7:45 Inizio lavoro Arrivo alla scrivania dopo aver fatto sport, dopo aver respirato aria aperta, dopo aver avuto il tempo di pensare. Non arrivo dopo aver combattuto una guerra.\nLa differenza non è solo fisica. È cognitiva.\nUn consulente IT lavora con la testa. Analizza sistemi, scrive codice, progetta architetture, risolve problemi complessi. Se quella testa arriva in ufficio già scarica, già frustrata, già stanca — quanto vale davvero quella giornata di lavoro?\nHo lavorato con team distribuiti su tre fusi orari. Ho gestito database critici collegandomi da casa alle 3 di notte per un\u0026rsquo;emergenza. Non ho mai avuto bisogno di un ufficio per fare il mio lavoro. Ho avuto bisogno di una connessione stabile, di un ambiente silenzioso, e di una mente lucida.\n📊 I numeri per l\u0026rsquo;azienda: quello che i CFO non vogliono vedere #Le aziende di consulenza IT a Roma hanno un problema strutturale che fingono di non avere.\nPrendiamo un\u0026rsquo;azienda con 50 consulenti. Facciamo i conti:\nCosto del pendolarismo aziendale # Voce Calcolo Totale annuo Ore perse in auto (media 3h/giorno x 50 persone) 150 ore/giorno x 220 gg 33.000 ore/anno Valore ora consulente (costo azienda medio) 33.000 x 35€/ora ~1.155.000€/anno Affitto ufficio Roma (50 postazioni) ~800€/postazione/mese ~480.000€/anno Utenze, pulizie, manutenzione ~60.000€/anno Costo totale stimato ~1.695.000€/anno Un milione e settecentomila euro. Ogni anno. Per tenere cinquanta persone sedute nello stesso posto.\nScenario smart working (80% remoto) # Voce Calcolo Totale annuo Ore recuperate (80% delle 33.000) 26.400 ore convertite in lavoro produttivo Ufficio ridimensionato (15 postazioni hot-desk) ~800€ x 15 ~144.000€/anno Contributo connettività dipendenti 50€/mese x 50 ~30.000€/anno Budget attrezzatura home office (una tantum) 1.000€ x 50 50.000€ (anno 1) Costo totale stimato (anno 1) ~224.000€ Costo totale stimato (dal anno 2) ~174.000€ Risparmio annuo: oltre 1.400.000€.\nE sto facendo stime conservative.\nMa il numero più importante non è quello economico.\nIl numero più importante sono quelle 26.400 ore restituite alla produttività.\nOre in cui le persone lavorano lucide, riposate, concentrate.\nNon ore in cui fissano un paraurti sulla Cristoforo Colombo.\n🧠 L\u0026rsquo;argomento che nessuno ha il coraggio di fare #Lo dico chiaramente: il presenteismo in ufficio nella consulenza IT è un retaggio culturale, non una necessità operativa.\nIl consulente informatico non lavora in catena di montaggio. Non ha bisogno di essere fisicamente presente accanto a una macchina. Ha bisogno di:\nuna connessione internet veloce un ambiente silenzioso strumenti digitali adeguati comunicazione chiara con il team obiettivi misurabili Tutto questo si fa meglio da casa che in un open space rumoroso dove il telefono squilla ogni cinque minuti e qualcuno ti interrompe per chiederti \u0026ldquo;hai un minuto?\u0026rdquo; (che non è mai un minuto).\nIl vero problema è il controllo. Alcune aziende non sanno gestire il lavoro per obiettivi. Sanno solo gestire la presenza. E confondono le due cose.\nSe un consulente chiude 20 ticket in una settimana lavorando da casa in pantaloncini, è più produttivo di uno che ne chiude 8 standosene in giacca e cravatta in ufficio dalle 9 alle 18.\nI numeri non mentono. Le sedie in ufficio sì.\n🏢 \u0026ldquo;Ma la cultura aziendale? Lo spirito di squadra?\u0026rdquo; #Lo sento dire spesso. Lo capisco. Non lo condivido, ma lo capisco.\nLa cultura aziendale non si costruisce facendo sedere le persone vicine. Si costruisce con:\nobiettivi condivisi che tutti capiscono comunicazione trasparente che nessuno subisce momenti di incontro che hanno un senso — non la riunione settimanale dove tutti guardano il telefono sotto il tavolo fiducia reciproca — che è esattamente quello che manca quando imponi la presenza Un team che lavora bene da remoto è un team che ha imparato a comunicare per davvero. Non per prossimità fisica, ma per chiarezza.\nHo visto team in ufficio che non si parlavano. E team distribuiti su tre paesi che funzionavano come orologi svizzeri.\nLa differenza non è il luogo. È il metodo.\n🎯 La proposta concreta #Se gestisci un\u0026rsquo;azienda di consulenza IT a Roma — o in qualsiasi grande città con problemi di mobilità — ecco quello che ti suggerisco:\n1. Adotta un modello 80/20\n80% remoto, 20% in presenza. I giorni in ufficio servono per workshop, review di progetto, momenti di team building reali — non per scaldare la sedia.\n2. Investi nella postazione domestica\n1.000€ una tantum per ogni dipendente: monitor, sedia ergonomica, cuffie con microfono. È un investimento che si ripaga in due settimane di risparmio affitto.\n3. Misura i risultati, non le ore\nDefinisci KPI chiari: ticket chiusi, codice rilasciato, SLA rispettati, clienti soddisfatti. Chi produce, produce — indipendentemente da dove si trova.\n4. Riduci gli spazi fisici\nPassa da 50 postazioni fisse a 15 hot desk. Usa lo spazio risparmiato per una sala riunioni degna di questo nome e un\u0026rsquo;area relax vera.\n5. Dai fiducia alle persone\nSe hai assunto professionisti, trattali da professionisti. Se non ti fidi di loro senza vederli, il problema non è lo smart working. È il processo di selezione.\n💬 A chi si riconosce in questa storia #Se ogni mattina ti alzi un\u0026rsquo;ora prima del necessario per \u0026ldquo;battere il traffico\u0026rdquo; — e arrivi comunque tardi.\nSe spendi 500€ al mese per il privilegio di stare seduto in coda.\nSe arrivi alla scrivania già stanco, già nervoso, già con la giornata compromessa.\nSappi che non deve essere così.\nEsiste un modo diverso di lavorare. Più intelligente. Più umano. Più produttivo.\nE i numeri lo dimostrano.\nNon servono rivoluzioni. Serve il coraggio di guardare quei numeri.\nE di agire di conseguenza.\nIo nel frattempo domattina mi alzo alle 6, vado a correre, e alle 7:45 sono operativo.\nCon il sorriso. Senza traffico. Senza stress.\nE con la testa già sul primo problema da risolvere.\nGlossario #Smart Working — Modello di lavoro flessibile che combina lavoro da remoto e presenza in ufficio, basato su obiettivi misurabili invece che su orari e presenza fisica.\nPendolarismo — Spostamento quotidiano casa-lavoro e ritorno, che nelle grandi città può assorbire 2-4 ore al giorno e centinaia di euro al mese.\nPresenteismo — Cultura organizzativa che equipara la presenza fisica in ufficio alla produttività, indipendentemente dai risultati effettivamente prodotti.\nKPI — Key Performance Indicator — metrica misurabile che valuta l\u0026rsquo;efficacia di un\u0026rsquo;attività rispetto a un obiettivo definito, usata per misurare risultati concreti invece di ore di presenza.\nHot Desk — Modello di organizzazione degli spazi ufficio in cui le postazioni non sono assegnate: chi viene in ufficio occupa una scrivania libera.\n","date":"24 febbraio 2026","permalink":"https://ivanluminaria.com/it/posts/project-management/smartworking-consulenza-it/","section":"Database Strategy","summary":"\u003cp\u003eOre 6:47 di un martedì qualunque. Sono al parco sotto casa, in tenuta da corsa. L\u0026rsquo;aria è fresca, il sole sta appena salendo. Ho già fatto quattro chilometri. Mi sento vivo.\u003c/p\u003e\n\u003cp\u003eAlle 7:00 sono sotto la doccia. Alle 7:20 faccio colazione con calma. Alle 7:45 sono alla scrivania, fresco, concentrato, pronto a lavorare.\u003c/p\u003e\n\u003cp\u003eA quell\u0026rsquo;ora, un mio collega è ancora fermo sulla Pontina. O sul raccordo, tra Casilina e Tuscolana. Ha già il telefono in mano — non per lavorare, ma per mandare il classico messaggio: \u0026ldquo;Scusa, arrivo tardi, c\u0026rsquo;è un incidente.\u0026rdquo;\u003c/p\u003e","title":"Smart working nella consulenza IT: i numeri che nessuno vuole guardare"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/tuning/","section":"Tags","summary":"","title":"Tuning"},{"content":"In circa trent’anni di lavoro non ho cambiato mestiere.\nHo cambiato profondità.\nOgni ruolo che ho ricoperto non è stato un salto laterale.\nÈ stato un approfondimento verticale.\nQuello che oggi offro non è un elenco di competenze.\nÈ la somma delle conseguenze che quelle competenze producono.\nData Warehouse Architect #La mia esperienza nel Data Warehouse si è sviluppata in contesti dove il dato è infrastruttura critica.\nHo lavorato per grandi operatori Telco come TIM, Wind, Vodafone e 3, in progetti internazionali con Huawei,\nin ambito assicurativo con Generali,\nin ambito istituzionale con Banca d’Italia, Ufficio Italiano Cambi e Cassa Depositi e Prestiti,\nnel settore Farmaceutico e nel settore Automotive con Rover e Alfa Romeo.\nSettori diversi, stessa esigenza: affidabilità.\nNel Telco conta la scala.\nNel Banking e nelle istituzioni conta la precisione normativa.\nNelle assicurazioni conta la coerenza del rischio.\nNel farmaceutico conta la compliance.\nNell’automotive conta la sincronizzazione dei processi e la qualità del dato lungo la filiera.\nHo progettato architetture dati in ambienti dove il margine di errore non è contemplato.\n👉 Leggi la roadmap delle mie competenze ed esperienze come Data Warehouse Architect | Scarica PDF\nProject Manager con background tecnico #La gestione di progetto è maturata coordinando attività in contesti complessi:\nTelecomunicazioni internazionali, Istituzioni finanziarie centrali, Assicurazioni, Farmaceutico, Automotive e Pubblica Amministrazione.\nIn questi settori, l’errore ha un costo reale.\nUn Project Manager tecnico conosce l’impatto delle scelte. Sa quando un compromesso è accettabile. E quando non lo è.\nCollego visione strategica e dettaglio tecnico. Roadmap e implementazione. Decisioni e conseguenze.\n👉 Leggi la roadmap delle mie competenze ed esperienze come Project Manager | Scarica PDF\nOracle DBA \u0026amp; Performance Tuning Expert #La mia attività come Oracle DBA si è consolidata in ambienti mission-critical per operatori come TIM, Wind, Vodafone e 3, in contesti tecnologici complessi come Huawei, per istituzioni finanziarie come Banca d’Italia, Ufficio Italiano Cambi e Cassa Depositi e Prestiti, per realtà assicurative come Generali, e in progetti industriali in ambito Automotive.\nSistemi ad alta disponibilità. Carichi elevati. Reperibilità reale.\nQui il tuning non è un miglioramento estetico. È protezione dell’operatività.\n👉 Leggi la roadmap delle mie competenze ed esperienze come Oracle DBA | Scarica PDF\nOracle PL/SQL – Senior \u0026amp; Mentor #Ho sviluppato PL/SQL in ambienti Telco, Banking, Assicurazioni, Automotive, Farmaceutico e Pubblica Amministrazione.\nIn contesti come Generali o Banca d’Italia, la logica nel database è parte della stabilità del sistema. In ambito Automotive, la coerenza dei dati impatta direttamente processi produttivi e supply chain.\nPer anni ho insegnato SQL e PL/SQL, contribuendo alla crescita tecnica di sviluppatori che oggi operano su sistemi complessi.\nOggi non mi limito a scrivere codice. Posso guidare. Posso fare mentoring. Posso aiutare sviluppatori a crescere in profondità tecnica e progettuale.\n👉 Leggi la roadmap delle mie competenze ed esperienze come Oracle PL/SQL Developer | Scarica PDF\n","date":null,"permalink":"https://ivanluminaria.com/it/resumes/","section":"Know-How e Impatto","summary":"\u003cp\u003eIn circa trent’anni di lavoro non ho cambiato mestiere.\u003c/p\u003e\n\u003cp\u003eHo cambiato profondità.\u003c/p\u003e\n\u003cp\u003eOgni ruolo che ho ricoperto non è stato un salto laterale.\u003cbr\u003e\nÈ stato un approfondimento verticale.\u003c/p\u003e\n\u003cp\u003eQuello che oggi offro non è un elenco di competenze.\u003cbr\u003e\nÈ la somma delle conseguenze che quelle competenze producono.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"data-warehouse-architect\" class=\"relative group\"\u003eData Warehouse Architect \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#data-warehouse-architect\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa mia esperienza nel Data Warehouse si è sviluppata in contesti dove il dato è infrastruttura critica.\u003c/p\u003e","title":"Know-How e Impatto"},{"content":" IVAN LUMINARIA Oracle, PostgreSQL \u0026 MySQL Expert | DWH Architect | Project Manager Professionista IT con circa 30 anni di esperienza nella progettazione, implementazione e gestione di soluzioni database e Data Warehouse in ambienti Oracle, PostgreSQL e MySQL. LinkedIn: ivanluminaria\nEmail: ivan (dot) luminaria (at) gmail (dot) com Lavoro con i database da circa trent’anni.\nSufficienti per aver visto cambiare motori, linguaggi, mode e slogan.\nSufficienti per sapere che, sotto la superficie, le leggi non cambiano mai.\nUn database non è un contenitore.\nÈ un organismo.\nRespira.\nSi affatica.\nSi blocca.\nOppure scala.\nHo iniziato in ambienti Oracle quando “mission-critical” non era una parola da slide.\nEra la differenza tra un sistema che regge e uno che crolla alle tre di notte.\nHo passato innumerevoli ore su AWR, ASH, piani di esecuzione.\nHo visto sistemi rallentare senza un motivo apparente.\nE ho imparato che un motivo c’è sempre.\nSolo che va cercato con metodo.\nPoi sono arrivati PostgreSQL e MySQL.\nStrumenti diversi.\nFilosofie diverse.\nStessa disciplina.\nCapire il motore.\nNon combatterlo.\nNon credo nelle ottimizzazioni miracolose.\nCredo nelle statistiche aggiornate.\nNel modello dati corretto.\nNella differenza tra “funziona” e “regge”.\nPerché un database lento non è un problema tecnico.\nÈ un problema di business.\nÈ un report che non arriva.\nÈ un cliente che aspetta.\nÈ una decisione presa in ritardo.\nE a me piace stare esattamente lì.\nNel punto in cui la tecnica incontra l’impatto reale.\nCome lavoro #Non mi limito ad “amministrare” database.\nLi osservo.\nLi misuro.\nLi metto sotto stress.\nLi metto in sicurezza.\nMi occupo di performance tuning su sistemi complessi — Oracle, RAC, Exadata — ma anche di PostgreSQL e MySQL in contesti moderni, spesso open source, dove l’assenza di “magia proprietaria” obbliga a capire davvero cosa succede sotto il cofano.\nProgetto architetture Data Warehouse perché i dati non servono a essere accumulati.\nServono a essere capiti.\nHo lavorato su modelli multidimensionali, processi ETL/ELT, flussi che devono essere affidabili prima ancora che veloci.\nPerché un dato sbagliato, anche se arriva in millisecondi, resta sbagliato.\nScrivo PL/SQL quando serve.\nOttimizzo quando è necessario.\nRifattorizzo quando è inevitabile.\nNon mi interessa l’effetto speciale.\nMi interessa la solidità.\nVisione #Negli anni ho integrato la profondità tecnica con una visione più ampia.\nHo coordinato piccoli team internazionali.\nHo tradotto esigenze di business in scelte tecniche sostenibili.\nHo imparato che la complessità non si elimina.\nSi governa.\nAgile, Scrum, processi strutturati: strumenti utili.\nMa senza competenza reale restano etichette.\nPer me leadership significa una cosa semplice:\nprendere decisioni tecniche che reggano nel tempo.\nFuori dal database #Fuori dal lavoro coltivo passioni che, in fondo, parlano la stessa lingua.\nLa fotografia mi ha insegnato che la luce giusta cambia la storia.\nLa musica — sto imparando il sax, con la pazienza di chi sa di non sapere ancora — mi ricorda che la tecnica senza sensibilità è solo rumore.\nLa chitarra mi tiene ancorato al ritmo.\nLa cucina è architettura commestibile: equilibrio, tempi, proporzioni.\nGli scacchi sono strategia pura: ogni mossa è una scelta, ogni scelta ha conseguenze.\nForse è per questo che mi trovo bene nei sistemi complessi.\nNon mi spaventano.\nMi incuriosiscono.\nMi piace entrare nel dettaglio.\nMa solo per far funzionare meglio l’insieme.\nNon costruisco database.\nCostruisco solidità.\n\u0026ldquo;Trasformo la complessità dei dati in valore strategico per il business.\u0026rdquo;\n","date":"20 febbraio 2026","permalink":"https://ivanluminaria.com/it/about/","section":"Ivan Luminaria","summary":"\u003cdiv class=\"profile-header flex flex-col sm:flex-row sm:items-center items-start\"\u003e\n  \u003cdiv class=\"flex-none\"\u003e\n    \u003cimg\n      src='https://ivanluminaria.com/img/ivan_luminaria_avatar.png'\n      alt=\"Ivan Luminaria\"\n      class=\"profile-avatar rounded-full shadow-xl border-4 border-slate-100\"\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"profile-text text-left\"\u003e\n    \u003ch1 class=\"mb-1\"\u003eIVAN LUMINARIA\u003c/h1\u003e\n    \u003ch3 class=\"mt-0 text-slate-500\"\u003e\n      Oracle, PostgreSQL \u0026 MySQL Expert | DWH Architect | Project Manager\n    \u003c/h3\u003e\n    \u003cp class=\"mt-4\"\u003e\n      Professionista IT con circa \u003cstrong\u003e30 anni di esperienza\u003c/strong\u003e nella progettazione, implementazione e gestione di soluzioni database e Data Warehouse in ambienti Oracle, PostgreSQL e MySQL.\n    \u003c/p\u003e\n    \u003cp class=\"mt-2\" style=\"font-size: 0.9em;\"\u003e\n      \u003cstrong\u003eLinkedIn:\u003c/strong\u003e \u003ca href=\"https://www.linkedin.com/in/ivanluminaria/\" target=\"_blank\" rel=\"noopener\"\u003eivanluminaria\u003c/a\u003e\u003cbr\u003e\n      \u003cstrong\u003eEmail:\u003c/strong\u003e ivan (dot) luminaria (at) gmail (dot) com\n    \u003c/p\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003chr\u003e\n\u003cp\u003eLavoro con i database da circa trent’anni.\u003c/p\u003e\n\u003cp\u003eSufficienti per aver visto cambiare motori, linguaggi, mode e slogan.\u003cbr\u003e\nSufficienti per sapere che, sotto la superficie, le leggi non cambiano mai.\u003c/p\u003e","title":"Chi sono"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/cluster/","section":"Tags","summary":"","title":"Cluster"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/galera/","section":"Tags","summary":"","title":"Galera"},{"content":"Il ticket era laconico, come spesso accade quando il problema è grave: \u0026ldquo;Il database è andato giù di nuovo. L\u0026rsquo;applicazione è ferma. Terza volta in due mesi.\u0026rdquo;\nIl cliente aveva un MariaDB su un singolo server Linux — un\u0026rsquo;applicazione gestionale usata da circa duecento utenti interni, con picchi di carico durante le chiusure contabili di fine mese. Ogni volta che il server aveva un problema — un disco che rallentava, un aggiornamento di sistema che richiedeva un riavvio, un processo che consumava tutta la RAM — il database cadeva e con lui l\u0026rsquo;intera operatività aziendale.\nLa domanda non era \u0026ldquo;come ripariamo il server\u0026rdquo;. La domanda era: come facciamo in modo che la prossima volta che un server ha un problema, l\u0026rsquo;applicazione continui a funzionare?\nLa risposta, dopo vent\u0026rsquo;anni di esperienza con questo tipo di scenari, era una: Galera Cluster.\nLa diagnosi: un single point of failure classico #La prima cosa che ho fatto è stata analizzare l\u0026rsquo;infrastruttura. Il quadro era familiare:\nUn singolo server MariaDB, nessuna replica Backup notturno su disco esterno (almeno quello) Nessun meccanismo di failover L\u0026rsquo;applicazione puntava direttamente all\u0026rsquo;IP del server database Ogni downtime, anche di dieci minuti, significava duecento persone ferme. Durante le chiusure contabili, significava ritardi che si propagavano a cascata sui processi aziendali.\nHo proposto al cliente una soluzione basata su Galera Cluster: tre nodi MariaDB con replica sincrona multi-master. Qualsiasi nodo accetta letture e scritture, i dati sono coerenti su tutti e tre, e se un nodo cade gli altri due continuano a servire l\u0026rsquo;applicazione senza interruzione.\nIl cliente aveva già a disposizione tre VM Linux — il team infrastruttura le aveva provisioned per un altro progetto poi rimandato. Perfetto: non serviva nemmeno ordinare hardware.\nIl piano: tre nodi, zero single point of failure #Le macchine a disposizione:\nNodo Hostname IP Nodo 1 db-node1 10.0.1.11 Nodo 2 db-node2 10.0.1.12 Nodo 3 db-node3 10.0.1.13 Una premessa importante: Galera non è un\u0026rsquo;opzione nativa di MySQL Community. Si usa MariaDB (che lo integra nativamente) oppure Percona XtraDB Cluster (basato su MySQL). Il cliente usava già MariaDB, quindi la scelta era naturale e non richiedeva migrazione di engine.\nL\u0026rsquo;obiettivo era chiaro: migrare da un\u0026rsquo;architettura a singolo nodo a un cluster a tre nodi, senza cambiare l\u0026rsquo;applicazione se non per l\u0026rsquo;indirizzo di connessione.\nInstallazione: stessa versione su tutti i nodi #Primo principio non negoziabile: tutti i nodi devono avere la stessa identica versione di MariaDB. Ho visto cluster instabili per mesi perché qualcuno aveva aggiornato un nodo e non gli altri.\nSu tutti e tre i server:\n# Aggiungere il repository ufficiale MariaDB (esempio per 11.4 LTS) curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | \\ sudo bash -s -- --mariadb-server-version=\u0026#34;mariadb-11.4\u0026#34; # Installare MariaDB Server e il plugin Galera sudo dnf install MariaDB-server MariaDB-client galera-4 -y # Abilitare ma NON avviare ancora il servizio sudo systemctl enable mariadb Non avviare il servizio. Prima si configura. Sempre.\nIl cuore della configurazione: /etc/my.cnf.d/galera.cnf #Questo è il file che definisce il comportamento del cluster. Va creato su ogni nodo, con le dovute differenze per indirizzo IP e nome nodo.\nEcco la configurazione completa per il Nodo 1:\n[mysqld] # === Motore e charset === binlog_format=ROW default_storage_engine=InnoDB innodb_autoinc_lock_mode=2 innodb_flush_log_at_trx_commit=2 innodb_buffer_pool_size=1G # === Configurazione WSREP (Galera) === wsrep_on=ON wsrep_provider=/usr/lib64/galera-4/libgalera_smm.so # Lista di TUTTI i nodi del cluster wsrep_cluster_address=\u0026#34;gcomm://10.0.1.11,10.0.1.12,10.0.1.13\u0026#34; # Nome del cluster (deve essere identico su tutti i nodi) wsrep_cluster_name=\u0026#34;galera_produzione\u0026#34; # Identità di QUESTO nodo (cambia su ogni server) wsrep_node_address=\u0026#34;10.0.1.11\u0026#34; wsrep_node_name=\u0026#34;db-node1\u0026#34; # Metodo SST (State Snapshot Transfer) wsrep_sst_method=mariabackup wsrep_sst_auth=\u0026#34;sst_user:password_sicura_qui\u0026#34; # === Rete === bind-address=0.0.0.0 Per il Nodo 2 e il Nodo 3, l\u0026rsquo;unica cosa che cambia è:\n# Nodo 2 wsrep_node_address=\u0026#34;10.0.1.12\u0026#34; wsrep_node_name=\u0026#34;db-node2\u0026#34; # Nodo 3 wsrep_node_address=\u0026#34;10.0.1.13\u0026#34; wsrep_node_name=\u0026#34;db-node3\u0026#34; Tutto il resto è identico. Identico. Non cedere alla tentazione di \u0026ldquo;personalizzare\u0026rdquo; buffer pool o altri parametri per nodo: in un cluster Galera, la simmetria è una virtù.\nPerché ogni parametro conta #Vediamo i parametri uno per uno, perché ognuno ha una ragione precisa.\nbinlog_format=ROW #Galera richiede il formato ROW per il binary log. Non STATEMENT, non MIXED. ROW e basta. Con gli altri formati il cluster non si avvia nemmeno — e giustamente, perché la replica sincrona basata su certification dipende dalla precisione a livello di riga.\ninnodb_autoinc_lock_mode=2 #Questo parametro imposta il lock mode per gli auto-increment a \u0026ldquo;interleaved\u0026rdquo;. In un cluster multi-master, due nodi possono generare INSERT contemporaneamente sulla stessa tabella. Con il lock mode 1 (il default) si creerebbero deadlock. Con il valore 2, InnoDB genera gli auto-increment senza lock globale, permettendo inserimenti concorrenti da nodi diversi.\nLa conseguenza: gli ID auto-increment non saranno sequenziali tra i nodi. Se la tua applicazione dipende dalla sequenzialità degli ID, hai un problema architetturale da risolvere a monte.\ninnodb_flush_log_at_trx_commit=2 #Qui si fa un compromesso consapevole. Il valore 1 (default) garantisce durabilità totale — ogni commit viene scritto e fsynced sul disco. Ma in un cluster Galera, la durabilità è già garantita dalla replica sincrona su tre nodi. Il valore 2 scrive nel buffer del sistema operativo ad ogni commit e fa fsync solo ogni secondo, migliorando le performance di scrittura del 30-40% nei nostri test.\nSe perdi un nodo, i dati sono sugli altri due. Se perdi il datacenter intero\u0026hellip; beh, quello è un altro discorso.\nwsrep_sst_method=mariabackup #SST è il meccanismo con cui un nodo che si unisce al cluster riceve una copia completa dei dati. Le opzioni sono:\nMetodo Pro Contro rsync Veloce Il nodo donatore si blocca in lettura mariabackup Non blocca il donatore Richiede installazione separata mysqldump Semplice Lentissimo, blocca il donatore Sempre mariabackup. In produzione, bloccare un nodo donatore durante un SST significa degradare il cluster nel momento in cui ne hai più bisogno.\n# Installare mariabackup su tutti i nodi sudo dnf install MariaDB-backup -y Firewall: le porte che Galera vuole aperte #Questo è il punto dove vedo fallire il 50% delle prime installazioni. Galera non usa solo la porta MySQL.\n# Su tutti e tre i nodi sudo firewall-cmd --permanent --add-port=3306/tcp # MySQL standard sudo firewall-cmd --permanent --add-port=4567/tcp # Comunicazione cluster Galera sudo firewall-cmd --permanent --add-port=4567/udp # Multicast replication (opzionale) sudo firewall-cmd --permanent --add-port=4568/tcp # IST (Incremental State Transfer) sudo firewall-cmd --permanent --add-port=4444/tcp # SST (State Snapshot Transfer) sudo firewall-cmd --reload Se SELinux è attivo (e dovrebbe esserlo), servono anche le policy:\nsudo setsebool -P mysql_connect_any 1 Quattro porte. Quattro. Non una di più, non una di meno. Se ne dimentichi una, il cluster si forma ma non sincronizza — e il debug diventa un esercizio di frustrazione.\nLa migrazione dei dati e il bootstrap #Prima di avviare il cluster, ho migrato i dati dal server standalone al Nodo 1 con un dump completo:\n# Sul vecchio server standalone mysqldump --all-databases --single-transaction --routines --triggers \\ --events \u0026gt; /tmp/full_dump.sql # Trasferimento sul Nodo 1 scp /tmp/full_dump.sql db-node1:/tmp/ Poi il bootstrap — il momento della verità. Il primo nodo non si avvia con systemctl start mariadb. Si avvia con il comando di bootstrap.\nSolo sul Nodo 1:\nsudo galera_new_cluster Questo comando avvia MariaDB con wsrep_cluster_address=gcomm:// (vuoto), che significa: \u0026ldquo;Io sono il fondatore, non cerco altri nodi.\u0026rdquo;\nImportazione dei dati e creazione dell\u0026rsquo;utente SST:\n-- Importare il dump dal vecchio server SOURCE /tmp/full_dump.sql; -- Creare l\u0026#39;utente per il trasferimento dati tra nodi CREATE USER \u0026#39;sst_user\u0026#39;@\u0026#39;localhost\u0026#39; IDENTIFIED BY \u0026#39;password_sicura_qui\u0026#39;; GRANT RELOAD, PROCESS, LOCK TABLES, REPLICATION CLIENT ON *.* TO \u0026#39;sst_user\u0026#39;@\u0026#39;localhost\u0026#39;; FLUSH PRIVILEGES; Verifica immediata:\nSHOW STATUS LIKE \u0026#39;wsrep_cluster_size\u0026#39;; -- +--------------------+-------+ -- | Variable_name | Value | -- +--------------------+-------+ -- | wsrep_cluster_size | 1 | -- +--------------------+-------+ Se il valore è 1, il bootstrap ha funzionato. Ora, sugli altri due nodi:\nsudo systemctl start mariadb Questi nodi leggono wsrep_cluster_address, trovano il Nodo 1, ricevono un SST completo con tutti i dati e si uniscono al cluster.\nDopo aver avviato tutti e tre:\nSHOW STATUS LIKE \u0026#39;wsrep_cluster_size\u0026#39;; -- +--------------------+-------+ -- | Variable_name | Value | -- +--------------------+-------+ -- | wsrep_cluster_size | 3 | -- +--------------------+-------+ Tre. Questo è il numero magico. Il momento in cui il cliente ha smesso di avere un single point of failure.\nVerificare lo stato di salute del cluster #Questa è la parte che interessa davvero a chi gestisce il cluster giorno per giorno. Non basta sapere che wsrep_cluster_size è 3. Bisogna sapere leggere lo stato completo.\nLa query diagnostica che uso sempre #SHOW STATUS WHERE Variable_name IN ( \u0026#39;wsrep_cluster_size\u0026#39;, \u0026#39;wsrep_cluster_status\u0026#39;, \u0026#39;wsrep_connected\u0026#39;, \u0026#39;wsrep_ready\u0026#39;, \u0026#39;wsrep_local_state_comment\u0026#39;, \u0026#39;wsrep_incoming_addresses\u0026#39;, \u0026#39;wsrep_evs_state\u0026#39;, \u0026#39;wsrep_flow_control_paused\u0026#39;, \u0026#39;wsrep_local_recv_queue_avg\u0026#39;, \u0026#39;wsrep_local_send_queue_avg\u0026#39;, \u0026#39;wsrep_cert_deps_distance\u0026#39; ); Come interpretare i risultati # Variabile Valore sano Cosa significa wsrep_cluster_size 3 Tutti i nodi sono nel cluster wsrep_cluster_status Primary Il cluster è operativo e ha quorum wsrep_connected ON Questo nodo è connesso al cluster wsrep_ready ON Questo nodo accetta query wsrep_local_state_comment Synced Questo nodo è sincronizzato wsrep_flow_control_paused 0.0 Nessuna pausa per flow control wsrep_local_recv_queue_avg \u0026lt; 0.5 La coda di ricezione è sotto controllo wsrep_local_send_queue_avg \u0026lt; 0.5 La coda di invio è sotto controllo I segnali di pericolo #wsrep_cluster_status = Non-Primary: il nodo ha perso il quorum. È isolato. Non accetterà scritture (e non deve). Questo succede quando un nodo perde la connessione con la maggioranza del cluster.\nwsrep_flow_control_paused \u0026gt; 0.0: flow control attivato. Significa che un nodo è troppo lento nell\u0026rsquo;applicare le transazioni e sta chiedendo agli altri di rallentare. Un valore vicino a 1.0 significa che il cluster è sostanzialmente fermo, in attesa del nodo più lento.\nwsrep_local_recv_queue_avg \u0026gt; 1.0: le transazioni in arrivo si accumulano. Potrebbe essere un problema di I/O disco, CPU, o un nodo sottodimensionato.\nScript di monitoraggio #Ho consegnato al cliente anche uno script per il loro sistema di monitoring (Zabbix, nel loro caso):\n#!/bin/bash # galera_health_check.sh — da eseguire su ogni nodo MYSQL=\u0026#34;mysql -u monitor -p\u0026#39;monitor_pwd\u0026#39; -Bse\u0026#34; CLUSTER_SIZE=$($MYSQL \u0026#34;SHOW STATUS LIKE \u0026#39;wsrep_cluster_size\u0026#39;\u0026#34; | awk \u0026#39;{print $2}\u0026#39;) CLUSTER_STATUS=$($MYSQL \u0026#34;SHOW STATUS LIKE \u0026#39;wsrep_cluster_status\u0026#39;\u0026#34; | awk \u0026#39;{print $2}\u0026#39;) NODE_STATE=$($MYSQL \u0026#34;SHOW STATUS LIKE \u0026#39;wsrep_local_state_comment\u0026#39;\u0026#34; | awk \u0026#39;{print $2}\u0026#39;) FLOW_CONTROL=$($MYSQL \u0026#34;SHOW STATUS LIKE \u0026#39;wsrep_flow_control_paused\u0026#39;\u0026#34; | awk \u0026#39;{print $2}\u0026#39;) if [ \u0026#34;$CLUSTER_SIZE\u0026#34; -lt 3 ] || [ \u0026#34;$CLUSTER_STATUS\u0026#34; != \u0026#34;Primary\u0026#34; ] || [ \u0026#34;$NODE_STATE\u0026#34; != \u0026#34;Synced\u0026#34; ]; then echo \u0026#34;CRITICAL: Galera cluster degradato\u0026#34; echo \u0026#34; Size: $CLUSTER_SIZE | Status: $CLUSTER_STATUS | State: $NODE_STATE | FC: $FLOW_CONTROL\u0026#34; exit 2 fi echo \u0026#34;OK: Galera cluster sano (3 nodi, Primary, Synced)\u0026#34; exit 0 Il problema dello split-brain : perché tre nodi e non due #Quando ho presentato la soluzione al cliente, la prima domanda è stata: \u0026ldquo;Servono davvero tre server? Non bastano due?\u0026rdquo;\nNo. E non è una questione di costo — è una questione di matematica.\nGalera usa un algoritmo di consenso basato su **quorum** . Con tre nodi, il quorum è 2: se un nodo cade, gli altri due riconoscono di essere la maggioranza e continuano a operare. Con due nodi, il quorum è 2: se un nodo cade, quello rimasto non ha quorum e si blocca per evitare lo split-brain.\nEsiste il parametro pc.ignore_quorum per forzare un nodo a operare senza quorum, ma è come disattivare l\u0026rsquo;allarme antincendio perché suona troppo spesso.\nTre nodi è il minimo per un cluster Galera in produzione. Il terzo nodo non è un lusso — è quello che permette al cluster di continuare a funzionare quando le cose vanno male.\nQuando un nodo va giù e torna su #Una delle prime cose che ho fatto dopo la messa in produzione è stata simulare un guasto — con il cliente che guardava.\nHo spento il Nodo 3. L\u0026rsquo;applicazione ha continuato a funzionare senza interruzione sui nodi 1 e 2. Nessun errore, nessun timeout. Duecento utenti che non si sono accorti di nulla.\nPoi ho riavviato il Nodo 3. Cosa è successo:\nIl nodo si è avviato e ha contattato gli altri tramite wsrep_cluster_address Il gap di transazioni era piccolo, quindi ha ricevuto un **IST** (Incremental State Transfer) — solo le transazioni mancanti In meno di un minuto era di nuovo Synced Se il nodo fosse rimasto giù più a lungo e il gcache fosse stato superato, avrebbe ricevuto un SST completo — l\u0026rsquo;intero dataset. Per questo il parametro gcache.size è importante:\nwsrep_provider_options=\u0026#34;gcache.size=512M\u0026#34; Un gcache più grande significa che il cluster può tollerare downtime più lunghi di un nodo senza dover fare un SST completo. Nel caso del cliente, con circa 80-100 MB di transazioni al giorno, un gcache di 512 MB copriva quasi una settimana di assenza.\nIl cliente ha guardato il Nodo 3 tornare in sync e ha detto: \u0026ldquo;Quindi la prossima volta che dobbiamo fare manutenzione su un server, non dobbiamo più fermare tutto?\u0026rdquo; Esatto. Quello era il punto.\nChecklist di messa in produzione #Prima di dichiarare il cluster pronto al cliente, ho verificato ogni punto:\nStessa versione MariaDB su tutti i nodi wsrep_cluster_size = 3 wsrep_cluster_status = Primary su tutti i nodi wsrep_local_state_comment = Synced su tutti i nodi Test di scrittura su Nodo 1, verifica lettura su Nodo 2 e 3 Test di shutdown di un nodo: il cluster continua a funzionare Test di rejoin: il nodo torna in Synced senza SST completo Utente SST configurato e funzionante Firewall verificato su tutte le porte (3306, 4567, 4568, 4444) Monitoring attivo su wsrep_cluster_status e wsrep_flow_control_paused Backup configurato (su UN nodo, non su tutti e tre) Applicazione riconfigurata per puntare al load balancer o al VIP Sei mesi dopo #Ho risentito il cliente sei mesi dopo la messa in produzione. Nel frattempo avevano avuto due riavvii programmati per aggiornamenti di sistema e un guasto imprevisto a un disco su uno dei nodi. In tutti e tre i casi, l\u0026rsquo;applicazione non ha mai smesso di funzionare. Zero downtime non pianificato.\nLa cosa che mi ha colpito di più è stata la sua frase: \u0026ldquo;Prima vivevamo con l\u0026rsquo;ansia del database che cadeva. Adesso non ci pensiamo più.\u0026rdquo;\nQuesto è il vero valore di un cluster Galera ben configurato. Non è la tecnologia in sé — è la tranquillità che porta. La certezza che un singolo guasto non ferma più l\u0026rsquo;azienda.\nLa parte tecnica è la più semplice. Quello che fa la differenza è capire perché ogni parametro è impostato in un certo modo, cosa succede quando le cose vanno male, e come diagnosticare i problemi prima che diventino emergenze. Un cluster che funziona in demo e uno che regge in produzione: la distanza tra i due è tutta nei dettagli che ho raccontato qui.\nGlossario #Quorum — Meccanismo di consenso basato sulla maggioranza dei nodi. Con 3 nodi il quorum è 2: se uno cade, gli altri due continuano a operare. È ciò che previene lo split-brain.\nSST — State Snapshot Transfer: meccanismo con cui un nodo che si unisce al cluster riceve una copia completa dell\u0026rsquo;intero dataset da un nodo donatore. Il metodo raccomandato è mariabackup.\nIST — Incremental State Transfer: trasferimento delle sole transazioni mancanti a un nodo che rientra nel cluster dopo un\u0026rsquo;assenza breve. Molto più veloce di un SST completo.\nWSREP — Write Set Replication: API e protocollo di replica sincrona usato da Galera Cluster. Ogni transazione viene replicata su tutti i nodi prima del commit tramite un processo di certification.\nSplit-brain — Condizione critica in cui due parti del cluster operano indipendentemente accettando scritture divergenti. Il quorum la previene: solo la partizione con la maggioranza dei nodi può continuare a operare.\n","date":"17 febbraio 2026","permalink":"https://ivanluminaria.com/it/posts/mysql/galera-cluster-3-nodi/","section":"Database Strategy","summary":"\u003cp\u003eIl ticket era laconico, come spesso accade quando il problema è grave: \u0026ldquo;Il database è andato giù di nuovo. L\u0026rsquo;applicazione è ferma. Terza volta in due mesi.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eIl cliente aveva un MariaDB su un singolo server Linux — un\u0026rsquo;applicazione gestionale usata da circa duecento utenti interni, con picchi di carico durante le chiusure contabili di fine mese. Ogni volta che il server aveva un problema — un disco che rallentava, un aggiornamento di sistema che richiedeva un riavvio, un processo che consumava tutta la RAM — il database cadeva e con lui l\u0026rsquo;intera operatività aziendale.\u003c/p\u003e","title":"Galera Cluster a 3 nodi: come ho risolto un problema di disponibilità su MySQL"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/high-availability/","section":"Tags","summary":"","title":"High-Availability"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/wsrep/","section":"Tags","summary":"","title":"Wsrep"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/ash/","section":"Tags","summary":"","title":"Ash"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/awr/","section":"Tags","summary":"","title":"Awr"},{"content":"Venerdì, ore 18:40. Ero già con il giubbotto addosso, pronto per uscire. Il telefono vibra. È il project manager.\n\u0026ldquo;Ivan, abbiamo un problema. Il sistema è lentissimo. Domani mattina c\u0026rsquo;è il go-live.\u0026rdquo;\nNon è la prima volta che ricevo una chiamata del genere. Ma il tono era diverso dal solito. Non era la lamentela generica sulla lentezza. Era panico.\nMi ricollego in VPN, apro una sessione sul database Oracle 19c del cliente. La prima cosa che faccio è un controllo rapido:\nSELECT metric_name, value FROM v$sysmetric WHERE metric_name IN (\u0026#39;Database CPU Time Ratio\u0026#39;, \u0026#39;Database Wait Time Ratio\u0026#39;, \u0026#39;Average Active Sessions\u0026#39;); CPU Time Ratio: 12%. In condizioni normali era sopra l'80%.\nAverage Active Sessions: 47. Su un server con 16 core.\nQuarantasette sessioni attive. Il database stava annegando.\n🔥 I sintomi #Il team di sviluppo aveva completato l\u0026rsquo;ultimo deploy del codice applicativo quel pomeriggio. Tutto sembrava funzionare sui test. Ma quando hanno lanciato il batch di verifica pre-go-live — quello che simula il carico di produzione — i tempi di risposta sono esplosi.\nLe query che normalmente giravano in 2-3 secondi ne impiegavano 45. I batch che finivano in 20 minuti erano ancora in esecuzione dopo un\u0026rsquo;ora. I wait event dominanti erano db file sequential read e db file scattered read — segno inequivocabile di I/O fisico massiccio.\nQualcosa stava leggendo enormi quantità di dati dal disco. Qualcosa che prima non c\u0026rsquo;era.\n📊 AWR: la fotografia del problema #AWR — Automatic Workload Repository — è lo strumento diagnostico più potente che Oracle mette a disposizione. Ogni ora, Oracle scatta un\u0026rsquo;istantanea (snapshot ) delle statistiche di performance e la conserva nel repository interno. Confrontando due snapshot, ottieni un report che ti dice esattamente cosa è successo in quel periodo.\nHo generato uno snapshot manuale per catturare la situazione attuale:\nEXEC DBMS_WORKLOAD_REPOSITORY.create_snapshot; Poi ho cercato gli snapshot disponibili:\nSELECT snap_id, begin_interval_time, end_interval_time FROM dba_hist_snapshot WHERE begin_interval_time \u0026gt; SYSDATE - 1/6 ORDER BY snap_id DESC; Avevo uno snapshot delle 18:00 (prima del problema visibile) e quello appena creato alle 18:45. Ho generato il report AWR:\nSELECT output FROM TABLE(DBMS_WORKLOAD_REPOSITORY.awr_report_text( l_dbid =\u0026gt; (SELECT dbid FROM v$database), l_inst_num =\u0026gt; 1, l_bid =\u0026gt; 4523, -- snapshot inizio l_eid =\u0026gt; 4524 -- snapshot fine )); Cosa diceva il report #La sezione Top 5 Timed Foreground Events era eloquente:\nEvent Waits Time (s) % DB time db file scattered read 1.247.832 3.847 58,2% db file sequential read 423.109 1.205 18,2% CPU + Wait for CPU — 892 13,5% log file sync 12.445 287 4,3% direct path read 8.221 198 3,0% db file scattered read al 58%. Sono full table scan . Qualcuno stava leggendo tabelle intere, blocco dopo blocco, senza usare indici.\nLa sezione SQL ordered by Elapsed Time mostrava un solo SQL_ID che consumava il 71% del tempo totale del database: g4f2h8k1nw3z9.\nOra sapevo cosa cercare.\n🔍 ASH: il microscopio #AWR mi aveva dato la fotografia d\u0026rsquo;insieme. Ma avevo bisogno di capire quando quel SQL era iniziato, chi lo eseguiva, e quale programma lo aveva lanciato.\nASH — Active Session History — registra lo stato di ogni sessione attiva una volta al secondo. È il microscopio del DBA: dove AWR ti mostra le medie su un\u0026rsquo;ora, ASH ti mostra cosa succedeva secondo per secondo.\nSELECT sample_time, session_id, sql_id, sql_plan_hash_value, event, program, module FROM v$active_session_history WHERE sql_id = \u0026#39;g4f2h8k1nw3z9\u0026#39; AND sample_time \u0026gt; SYSDATE - 1/24 ORDER BY sample_time DESC; I risultati erano chiari:\nProgram: JDBC Thin Client — l\u0026rsquo;applicazione Java del batch Module: BatchVerificaProduzione Event: db file scattered read nel 92% dei campioni Prima occorrenza: 17:12 — esattamente dopo il deploy del pomeriggio SQL_PLAN_HASH_VALUE: 2891047563 Il piano di esecuzione era cambiato. Prima del deploy, quella query usava un piano diverso.\n🧩 Il piano di esecuzione #Ho recuperato il piano corrente:\nSELECT * FROM TABLE(DBMS_XPLAN.display_awr( sql_id =\u0026gt; \u0026#39;g4f2h8k1nw3z9\u0026#39;, plan_hash_value =\u0026gt; 2891047563 )); Il risultato mi ha fatto capire subito il problema:\n--------------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | 48721 | | 1 | HASH JOIN | | 2.1M | 48721 | | 2 | TABLE ACCESS FULL | MOVIMENTI_TEMP | 2.1M | 41893 | | 3 | INDEX RANGE SCAN | IDX_CLIENTI_PK | 1 | 2 | --------------------------------------------------------------------------- TABLE ACCESS FULL su MOVIMENTI_TEMP. Una tabella temporanea con 2,1 milioni di righe, letta per intero ogni volta. Nessun indice. Nessun filtro efficace.\nHo verificato cosa esisteva prima del deploy controllando il piano precedente in AWR:\nSELECT plan_hash_value, timestamp FROM dba_hist_sql_plan WHERE sql_id = \u0026#39;g4f2h8k1nw3z9\u0026#39; ORDER BY timestamp; Il piano precedente (hash 1384726091) usava un INDEX RANGE SCAN su un indice che — scoperta — era stato eliminato durante il deploy. Lo script di migrazione includeva un DROP TABLE MOVIMENTI_TEMP seguito da una ricreazione, ma senza ricreare l\u0026rsquo;indice.\n⚡ La soluzione #Dieci minuti. Dal momento in cui mi ero collegato a quando ho identificato la causa. Non per bravura — per gli strumenti.\nLa fix era semplice:\nCREATE INDEX idx_movimenti_temp_cliente ON movimenti_temp (id_cliente, data_movimento) TABLESPACE idx_data; Dopo la creazione dell\u0026rsquo;indice, ho forzato un re-parse della query:\nEXEC DBMS_SHARED_POOL.purge(\u0026#39;g4f2h8k1nw3z9\u0026#39;, \u0026#39;C\u0026#39;); Ho chiesto al team di rilanciare il batch. Tempo di esecuzione: 18 minuti. Identico ai test precedenti.\nIl go-live del sabato mattina è andato regolarmente.\n📋 AWR vs ASH: quando usare cosa #Dopo quell\u0026rsquo;episodio ho formalizzato una regola che uso sempre:\nCaratteristica AWR ASH Granularità Snapshot orari (configurabili) Campione ogni secondo Profondità storica Fino a 30 giorni (default 8) 1 ora in memoria, poi in AWR Caso d\u0026rsquo;uso principale Trend analysis, confronto periodi Diagnosi puntuale, isolamento SQL Vista principale DBA_HIST_* V$ACTIVE_SESSION_HISTORY Vista storica — DBA_HIST_ACTIVE_SESS_HISTORY Licenza richiesta Diagnostic Pack Diagnostic Pack Output tipico Report HTML/text Query ad hoc La regola empirica: AWR per capire cosa è cambiato, ASH per capire perché.\nAWR ti dice: \u0026ldquo;Tra le 17:00 e le 18:00, il 58% del tempo del database è stato speso in full table scan.\u0026rdquo; ASH ti dice: \u0026ldquo;Alle 17:12:34, la sessione 847 stava eseguendo la query g4f2h8k1nw3z9 con un full table scan su MOVIMENTI_TEMP, lanciata dal programma BatchVerificaProduzione.\u0026rdquo;\nSono complementari. Usarne solo uno è come diagnosticare un problema guardando solo la TAC o solo gli esami del sangue.\n🛡️ Le query che ogni DBA dovrebbe avere pronte #Negli anni ho costruito un set di query diagnostiche che tengo sempre a portata di mano. Le condivido perché in un\u0026rsquo;emergenza non c\u0026rsquo;è tempo per scriverle da zero.\nTop SQL per tempo di esecuzione (ultima ora) #SELECT sql_id, COUNT(*) AS samples, ROUND(COUNT(*) / 60, 1) AS est_minutes, MAX(event) AS top_event, MAX(program) AS program FROM v$active_session_history WHERE sample_time \u0026gt; SYSDATE - 1/24 AND sql_id IS NOT NULL GROUP BY sql_id ORDER BY samples DESC FETCH FIRST 10 ROWS ONLY; Wait event distribution per un SQL specifico #SELECT event, COUNT(*) AS samples, ROUND(COUNT(*) * 100 / SUM(COUNT(*)) OVER(), 1) AS pct FROM v$active_session_history WHERE sql_id = \u0026#39;\u0026amp;sql_id\u0026#39; AND sample_time \u0026gt; SYSDATE - 1/24 GROUP BY event ORDER BY samples DESC; Confronto piani di esecuzione nel tempo #SELECT plan_hash_value, MIN(timestamp) AS first_seen, MAX(timestamp) AS last_seen, COUNT(*) AS executions_in_awr FROM dba_hist_sqlstat WHERE sql_id = \u0026#39;\u0026amp;sql_id\u0026#39; GROUP BY plan_hash_value ORDER BY first_seen; 🎯 Cosa ho imparato quella sera #Tre lezioni che porto con me.\nPrima: il deploy non è solo codice. È anche struttura. Quando rilasci in produzione, devi verificare che indici, constraint, statistiche e grant siano coerenti con quello che c\u0026rsquo;era prima. Uno script che fa DROP TABLE e CREATE TABLE senza ricreare gli indici è una bomba a orologeria.\nSeconda: AWR e ASH non sono strumenti per DBA senior. Sono strumenti di prima linea, come un defibrillatore. Devi saperli usare prima di averne bisogno, non durante l\u0026rsquo;emergenza.\nTerza: dieci minuti di diagnosi corretta valgono più di tre ore di tentativi alla cieca. Quando il sistema è in ginocchio, la tentazione è riavviare, uccidere sessioni, aumentare risorse. Ma senza sapere cosa sta succedendo, stai sparando nel buio.\nQuella sera sono uscito dall\u0026rsquo;ufficio alle 19:20. Quaranta minuti dopo la telefonata. Il giorno dopo il go-live è partito senza intoppi, e il lunedì il sistema girava regolarmente.\nNon sono un eroe. Ho solo usato gli strumenti giusti.\nGlossario #AWR — Automatic Workload Repository. Componente integrato in Oracle che raccoglie statistiche di performance tramite snapshot periodici e genera report diagnostici comparativi.\nASH — Active Session History. Componente Oracle che campiona lo stato di ogni sessione attiva una volta al secondo, conservandolo in memoria e poi in AWR. È il microscopio del DBA per la diagnosi puntuale.\nFull Table Scan — Operazione di lettura in cui Oracle legge tutti i blocchi di una tabella senza usare indici. Nei wait event compare come db file scattered read.\nWait Event — Evento di attesa registrato da Oracle ogni volta che una sessione non può procedere perché attende una risorsa (I/O, lock, CPU, rete). L\u0026rsquo;analisi dei wait event è la base della metodologia diagnostica Oracle.\nSnapshot — Istantanea delle statistiche di performance catturata periodicamente da AWR (di default ogni 60 minuti). Il confronto tra due snapshot genera il report AWR.\n","date":"10 febbraio 2026","permalink":"https://ivanluminaria.com/it/posts/oracle/oracle-awr-ash/","section":"Database Strategy","summary":"\u003cp\u003eVenerdì, ore 18:40. Ero già con il giubbotto addosso, pronto per uscire. Il telefono vibra. È il project manager.\u003c/p\u003e\n\u003cp\u003e\u0026ldquo;Ivan, abbiamo un problema. Il sistema è lentissimo. Domani mattina c\u0026rsquo;è il go-live.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eNon è la prima volta che ricevo una chiamata del genere. Ma il tono era diverso dal solito. Non era la lamentela generica sulla lentezza. Era panico.\u003c/p\u003e\n\u003cp\u003eMi ricollego in VPN, apro una sessione sul database Oracle 19c del cliente. La prima cosa che faccio è un controllo rapido:\u003c/p\u003e","title":"AWR, ASH e i 10 minuti che hanno salvato un go-live"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/diagnostic/","section":"Tags","summary":"","title":"Diagnostic"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/go-live/","section":"Tags","summary":"","title":"Go-Live"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/grant/","section":"Tags","summary":"","title":"Grant"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/privileges/","section":"Tags","summary":"","title":"Privileges"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/revoke/","section":"Tags","summary":"","title":"Revoke"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/roles/","section":"Tags","summary":"","title":"Roles"},{"content":"La prima volta che ho lavorato seriamente con PostgreSQL arrivavo da anni di altri database. Cercavo il comando CREATE USER. Lo trovavo. Poi vedevo CREATE ROLE. Poi ALTER USER. Poi ALTER ROLE.\nPer qualche minuto ho pensato: \u0026ldquo;Ok, qui qualcuno si diverte a confondere le persone\u0026rdquo;.\nIn realtà no. PostgreSQL è molto più coerente di quanto sembri. Solo che lo è a modo suo.\nIn PostgreSQL non esistono utenti. Esistono ruoli. #La chiave è questa: in PostgreSQL tutto è un ROLE.\nUn ROLE può:\navere il diritto di login\\ non avere il diritto di login\\ possedere oggetti\\ ereditare permessi da altri ruoli\\ essere usato come contenitore di privilegi Quello che in altri database chiami \u0026ldquo;utente\u0026rdquo; in PostgreSQL è semplicemente un ruolo con l\u0026rsquo;attributo LOGIN.\nInfatti:\nCREATE USER mario; non è altro che uno shortcut per:\nCREATE ROLE mario WITH LOGIN; Stessa cosa per ALTER USER: è solo un alias di ALTER ROLE.\nPerché esiste solo CREATE ROLE e ALTER ROLE?\nPerché PostgreSQL non distingue concettualmente tra utente e ruolo. È lo stesso oggetto con attributi diversi. Minimalista, elegante, coerente.\nSe un ruolo ha LOGIN, si comporta come un utente.\nSe non ha LOGIN, è un contenitore di permessi.\nQuando lo capisci davvero, cambia il modo in cui progetti la sicurezza.\nIl modello mentale corretto #Io oggi ragiono così:\nCreo ruoli \u0026ldquo;funzionali\u0026rdquo; che rappresentano insiemi di privilegi\\ Assegno quei ruoli agli utenti reali\\ Evito di dare permessi direttamente agli utenti Perché? Perché gli utenti cambiano. I ruoli no.\nSe domani arriva un nuovo collega, non riscrivo mezzo database di grant.\nGli assegno il ruolo giusto e fine.\nArchitettura pulita. Zero magia. Zero caos.\nUna storia vera (senza nomi imbarazzanti) #Tempo fa mi è stato chiesto di creare un utente di sola lettura per un sistema di monitoraggio.\nRichiesta apparentemente semplice: \u0026ldquo;Deve leggere alcune tabelle. Niente scrittura.\u0026rdquo;\nIl classico \u0026ldquo;tanto è solo read-only\u0026rdquo;.\nLa trappola è sempre la stessa: se fai solo un GRANT SELECT sulle tabelle esistenti, funziona oggi.\nTra tre mesi qualcuno crea una nuova tabella e il monitoraggio inizia a lanciare errori.\nE indovina chi viene chiamato.\nLa soluzione corretta richiede quattro livelli di attenzione:\nPermesso di connessione al database\\ Permesso di utilizzo dello schema (USAGE)\\ Permessi SELECT su tabelle e sequence esistenti\\ Default privileges per gli oggetti futuri Se salti un pezzo, prima o poi paghi il conto.\nEsempio: creazione di un utente read-only fatto bene #Supponiamo di voler creare un utente di sola lettura su due schemi.\nPrima creo il ruolo con login:\nCREATE ROLE srv_monitoraggio WITH LOGIN PASSWORD \u0026#39;PasswordSicura123#\u0026#39;; Lo metto in sicurezza:\nALTER ROLE srv_monitoraggio NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT; Permetto la connessione al database:\nGRANT CONNECT ON DATABASE mydb TO srv_monitoraggio; Permesso di usare gli schemi:\nGRANT USAGE ON SCHEMA schema1 TO srv_monitoraggio; GRANT USAGE ON SCHEMA schema2 TO srv_monitoraggio; Permessi di lettura sugli oggetti esistenti:\nGRANT SELECT ON ALL TABLES IN SCHEMA schema1 TO srv_monitoraggio; GRANT SELECT ON ALL TABLES IN SCHEMA schema2 TO srv_monitoraggio; GRANT SELECT ON ALL SEQUENCES IN SCHEMA schema1 TO srv_monitoraggio; GRANT SELECT ON ALL SEQUENCES IN SCHEMA schema2 TO srv_monitoraggio; E ora la parte che molti dimenticano:\nALTER DEFAULT PRIVILEGES IN SCHEMA schema1 GRANT SELECT ON TABLES TO srv_monitoraggio; ALTER DEFAULT PRIVILEGES IN SCHEMA schema2 GRANT SELECT ON TABLES TO srv_monitoraggio; Così anche le tabelle future saranno leggibili.\nNota importante: gli ALTER DEFAULT PRIVILEGES valgono per il ruolo che crea gli oggetti. Se più owner creano tabelle negli stessi schemi, la configurazione va replicata per ciascuno.\nPerché questo modello è potente #Il fatto che tutto sia un ROLE permette di costruire gerarchie pulite.\nEsempio evoluto:\nCREATE ROLE role_readonly; GRANT SELECT ON ALL TABLES IN SCHEMA schema1 TO role_readonly; CREATE ROLE srv_monitoraggio WITH LOGIN PASSWORD \u0026#39;...\u0026#39;; GRANT role_readonly TO srv_monitoraggio; Ora posso assegnare role_readonly a dieci utenti diversi senza duplicare grant.\nQuesto è design. Non è solo sintassi.\nConclusione #PostgreSQL non complica il concetto di utente. Lo semplifica.\nEsiste solo un tipo di oggetto: il ROLE. Sta a noi usarlo bene.\nSe lo tratti come un semplice \u0026ldquo;utente con password\u0026rdquo;, funziona.\nSe lo usi come mattoncino architetturale, diventa uno strumento potente per progettare sicurezza pulita, scalabile e manutenibile.\nLa differenza non sta nei comandi.\nSta nel modello mentale con cui li usi.\nGlossario #ROLE — Entità fondamentale di PostgreSQL che unifica il concetto di utente e gruppo di permessi: un ROLE con LOGIN è un utente, senza LOGIN è un contenitore di privilegi.\nDEFAULT PRIVILEGES — Meccanismo PostgreSQL che definisce automaticamente i privilegi da assegnare a tutti gli oggetti futuri creati in uno schema, evitando di dover ripetere i GRANT manualmente.\nSchema — Namespace logico all\u0026rsquo;interno di un database che raggruppa tabelle, viste, funzioni e altri oggetti, permettendo organizzazione e separazione dei permessi.\nGRANT — Comando SQL per assegnare privilegi specifici a un utente o ruolo su database, tabelle o colonne.\nLeast Privilege — Principio di sicurezza che prevede l\u0026rsquo;assegnazione a ogni utente solo dei permessi strettamente necessari per svolgere la propria funzione.\n","date":"10 febbraio 2026","permalink":"https://ivanluminaria.com/it/posts/postgresql/postgresql_roles_and_users/","section":"Database Strategy","summary":"\u003cp\u003eLa prima volta che ho lavorato seriamente con PostgreSQL arrivavo da\nanni di altri database. Cercavo il comando \u003ccode\u003eCREATE USER\u003c/code\u003e. Lo trovavo.\nPoi vedevo \u003ccode\u003eCREATE ROLE\u003c/code\u003e. Poi \u003ccode\u003eALTER USER\u003c/code\u003e. Poi \u003ccode\u003eALTER ROLE\u003c/code\u003e.\u003cbr\u003e\nPer qualche minuto ho pensato: \u0026ldquo;Ok, qui qualcuno si diverte a confondere\nle persone\u0026rdquo;.\u003c/p\u003e\n\u003cp\u003eIn realtà no. PostgreSQL è molto più coerente di quanto sembri. Solo che\nlo è a modo suo.\u003c/p\u003e\n\u003ch2 id=\"in-postgresql-non-esistono-utenti-esistono-ruoli\" class=\"relative group\"\u003eIn PostgreSQL non esistono utenti. Esistono ruoli. \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#in-postgresql-non-esistono-utenti-esistono-ruoli\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa chiave è questa: \u003cstrong\u003ein PostgreSQL tutto è un ROLE\u003c/strong\u003e.\u003c/p\u003e","title":"Ruoli e utenti in PostgreSQL: perché è tutto (solo) un ROLE"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/security/","section":"Tags","summary":"","title":"Security"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/bug-fixing/","section":"Tags","summary":"","title":"Bug-Fixing"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/github/","section":"Tags","summary":"","title":"Github"},{"content":"Mi chiama un cliente. Voce tesa, parole misurate.\n\u0026ldquo;Ivan, abbiamo un problema. Anzi, abbiamo il problema.\u0026rdquo;\nConosco quel tono. È il tono di chi ha già provato a risolvere le cose internamente, ha fallito, e adesso cerca qualcuno che gli dica la verità senza girarci intorno.\nIl problema è un software gestionale — non un sito web, non un\u0026rsquo;app — un sistema critico su cui girano processi aziendali importanti. Ha qualche anno di vita. È cresciuto in fretta, come succede sempre quando il business corre più veloce dell\u0026rsquo;architettura. E adesso si è accumulato tutto: bug aperti che nessuno chiude, richieste evolutive che nessuno pianifica, sviluppatori che lavorano su versioni diverse del codice senza sapere cosa fa l\u0026rsquo;altro.\nIl classico scenario che, a parole, \u0026ldquo;funziona\u0026rdquo;. Ma che dentro è un campo minato.\n🧠 Il primo incontro: capire cosa non funziona davvero #Quando entro in un progetto come questo, non guardo subito il codice.\nGuardo le persone. Guardo come comunicano. Guardo dove si perdono le informazioni.\nIl team era composto da quattro sviluppatori bravi. Seri. Competenti.\nMa lavoravano così:\nil codice stava su una cartella condivisa in rete le modifiche venivano comunicate via email o su un foglio Excel i bug venivano segnalati a voce, in chat, via ticket — senza un criterio unico nessuno sapeva con certezza quale fosse la versione \u0026ldquo;buona\u0026rdquo; del software E sai cosa succede in queste situazioni?\nSuccede che ognuno ha ragione dal suo punto di vista. Ma il progetto, nel suo insieme, è fuori controllo.\nIl problema non è tecnico. È organizzativo.\nE qui cambia tutto.\n📌 La proposta: GitHub come spina dorsale del progetto #La prima cosa che ho messo sul tavolo è stata chiara, diretta, senza fronzoli:\nAdottiamo GitHub. Tutto il codice passa da lì. Senza eccezioni.\nNon è una questione di moda. Non è perché \u0026ldquo;lo fanno tutti\u0026rdquo;.\nÈ perché GitHub risolve, con strumenti concreti, problemi che nessun foglio Excel potrà mai gestire:\nVersioning reale: ogni modifica è tracciata, commentata, reversibile Branch e Pull Request : ogni sviluppatore lavora sulla sua copia, poi propone le modifiche al team — non sovrascrive il lavoro degli altri Issue tracker integrato: i bug e le richieste evolutive vivono nello stesso posto del codice Cronologia completa: chi ha fatto cosa, quando, perché Ho visto la faccia dello sviluppatore senior. Un misto di curiosità e diffidenza.\n\u0026ldquo;Ma noi abbiamo sempre fatto così.\u0026rdquo;\nGli ho risposto con calma: \u0026ldquo;Lo so. E il risultato è il motivo per cui sono qui.\u0026rdquo;\nNon l\u0026rsquo;ho detto per provocare. L\u0026rsquo;ho detto perché è la verità.\nE la verità, quando viene detta nel modo giusto, non offende. Libera.\n🔬 Il secondo passo: l\u0026rsquo;AI come acceleratore, non come sostituto #Una volta definito il flusso di lavoro su GitHub — branch, review, merge controllati — ho fatto la seconda proposta.\n\u0026ldquo;Integriamo l\u0026rsquo;intelligenza artificiale nel processo di risoluzione dei bug.\u0026rdquo;\nSilenzio.\nCapisco la reazione. Quando dici \u0026ldquo;AI\u0026rdquo; in una stanza di sviluppatori, metà pensa a ChatGPT che genera codice a caso, l\u0026rsquo;altra metà pensa che gli stai dicendo che il loro lavoro non serve più.\nNessuna delle due cose.\nQuello che ho proposto è molto diverso:\nQuando uno sviluppatore prende in carico un bug, prima di scrivere una riga di codice, usa l\u0026rsquo;AI per analizzare il contesto L\u0026rsquo;AI legge il codice coinvolto, i log, la descrizione del problema Propone ipotesi. Non soluzioni definitive — ipotesi ragionate Lo sviluppatore valuta, verifica, e poi implementa L\u0026rsquo;AI non sostituisce il programmatore.\nL\u0026rsquo;AI gli fa risparmiare le prime due ore di analisi — quelle in cui stai leggendo codice scritto da qualcun altro, cercando di capire cosa diavolo succede.\nE quelle due ore, moltiplicate per ogni bug, per ogni sviluppatore, per ogni settimana, diventano un numero che cambia i conti del progetto.\n📊 I numeri che ho messo sul tavolo #Non ho venduto sogni. Ho presentato stime conservative.\nIl team gestiva mediamente 15-20 bug a settimana.\nIl tempo medio di risoluzione era di circa 6 ore per bug (tra analisi, fix, test, deploy).\nCon l\u0026rsquo;introduzione di GitHub + AI nel workflow, la mia stima era:\nMetrica Prima Dopo (stima) Tempo medio analisi bug ~2.5 ore ~15/20 minuti Tempo totale risoluzione ~6 ore ~30 minuti Bug risolti a settimana 15-20 180-240 Conflitti di codice frequenti rari Visibilità stato progetto nessuna completa Una riduzione di oltre il 90% sul tempo totale di risoluzione.\nUn aumento di 12 volte sulla capacità del team di chiudere i ticket.\nSenza assumere nessuno. Senza cambiare le persone. Cambiando il metodo.\n🛠️ Come funziona in pratica #Il workflow che ho disegnato è semplice. Volutamente semplice.\n1. Il bug arriva come Issue su GitHub\nTitolo chiaro, descrizione, label di priorità. Basta email, basta chat.\n2. Lo sviluppatore crea un branch dedicato\nfix/issue-234-errore-calcolo-iva — il nome dice tutto.\n3. Prima di toccare il codice, interroga l\u0026rsquo;AI\nLe passa il codice coinvolto, l\u0026rsquo;errore, il contesto. L\u0026rsquo;AI restituisce un\u0026rsquo;analisi strutturata: dove potrebbe essere il problema, quali file sono coinvolti, quali test verificare.\n4. Lo sviluppatore implementa il fix\nCon un vantaggio enorme: sa già dove guardare.\n5. Pull Request con review Un collega rivede il codice. Non per formalità — per qualità.\n6. Merge nel branch principale\nSolo dopo l\u0026rsquo;approvazione. Il codice \u0026ldquo;buono\u0026rdquo; resta sempre buono.\n7. L\u0026rsquo;Issue si chiude automaticamente\nTracciabilità completa. Dal problema alla soluzione, tutto documentato.\n📈 Cosa è cambiato dopo tre settimane #I primi giorni sono stati i più duri. Sempre così.\nNuovi strumenti, nuove abitudini, la tentazione di tornare al \u0026ldquo;come si faceva prima\u0026rdquo;.\nMa dopo tre settimane è successo qualcosa.\nLo sviluppatore senior — quello che mi aveva guardato con diffidenza — mi ha scritto:\n\u0026ldquo;Ivan, ieri ho risolto un bug che l\u0026rsquo;anno scorso mi aveva bloccato per due giorni. Con l\u0026rsquo;AI ci ho messo quaranta minuti. Non perché l\u0026rsquo;AI ha scritto il codice. Ma perché mi ha fatto vedere subito dove stava il problema.\u0026rdquo;\nEcco. Questo è il punto.\nL\u0026rsquo;AI non scrive codice migliore di uno sviluppatore esperto.\nL\u0026rsquo;AI accelera il percorso tra il problema e la comprensione del problema.\nE la comprensione è sempre il passaggio più costoso.\n🎯 La lezione che porto a casa #Ogni volta che entro in un progetto in difficoltà, trovo lo stesso schema:\nPersone competenti Strumenti inadeguati Processi assenti o informali Frustrazione crescente La soluzione non è mai \u0026ldquo;lavorare di più\u0026rdquo;.\nLa soluzione è lavorare in modo diverso.\nGitHub non è un tool per sviluppatori. È un tool per team.\nL\u0026rsquo;AI non è un giocattolo. È un moltiplicatore di competenza.\nMa nessuno dei due funziona se non c\u0026rsquo;è qualcuno che guarda il progetto dall\u0026rsquo;alto, capisce dove si perdono le ore, e ha il coraggio di dire: \u0026ldquo;Cambiamo.\u0026rdquo;\n💬 A chi si riconosce in questa storia #Se stai gestendo un progetto software e ti ritrovi in quello che ho descritto — il codice sparso, i bug che tornano, il team che lavora tanto ma chiude poco — sappi che non è colpa delle persone.\nÈ colpa del sistema in cui lavorano.\nE il sistema si può cambiare.\nSi deve cambiare.\nNon servono rivoluzioni. Servono scelte precise, implementate con metodo.\nUn repository condiviso. Un flusso di lavoro chiaro. Un assistente intelligente che accelera l\u0026rsquo;analisi.\nTre cose. Tre decisioni.\nChe trasformano il caos in controllo.\nGlossario #Pull Request — Richiesta formale di incorporare modifiche da un branch nel branch principale, con code review obbligatoria. Il meccanismo che garantisce che il codice \u0026ldquo;buono\u0026rdquo; resti buono.\nVersion Control — Sistema che traccia ogni modifica al codice, mantenendo la cronologia completa. Git è lo standard; GitHub aggiunge collaborazione sopra Git.\nIssue Tracker — Sistema di tracciamento integrato per bug e richieste evolutive. Su GitHub, le issue vivono nello stesso posto del codice, con tracciabilità dal problema alla soluzione.\nCode Review — Revisione del codice da parte di un collega prima del merge. Cattura bug, migliora la qualità e diffonde la conoscenza del codebase nel team.\nBranch — Ramo di sviluppo indipendente che permette di lavorare su modifiche isolate senza influenzare il codice principale fino al merge approvato.\n","date":"3 febbraio 2026","permalink":"https://ivanluminaria.com/it/posts/project-management/ai-github-project-management/","section":"Database Strategy","summary":"\u003cp\u003eMi chiama un cliente. Voce tesa, parole misurate.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u0026ldquo;Ivan, abbiamo un problema. Anzi, abbiamo \u003cstrong\u003eil\u003c/strong\u003e problema.\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eConosco quel tono. È il tono di chi ha già provato a risolvere le cose internamente, ha fallito, e adesso cerca qualcuno che gli dica la verità senza girarci intorno.\u003c/p\u003e\n\u003cp\u003eIl problema è un software gestionale — non un sito web, non un\u0026rsquo;app — un sistema critico su cui girano processi aziendali importanti. Ha qualche anno di vita. È cresciuto in fretta, come succede sempre quando il business corre più veloce dell\u0026rsquo;architettura. E adesso si è accumulato tutto: bug aperti che nessuno chiude, richieste evolutive che nessuno pianifica, sviluppatori che lavorano su versioni diverse del codice senza sapere cosa fa l\u0026rsquo;altro.\u003c/p\u003e","title":"Quando il caos diventa metodo: AI e GitHub per gestire un progetto che nessuno voleva toccare"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/software-evolution/","section":"Tags","summary":"","title":"Software-Evolution"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/workflow/","section":"Tags","summary":"","title":"Workflow"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/agile/","section":"Tags","summary":"","title":"Agile"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/audit/","section":"Tags","summary":"","title":"Audit"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/meeting/","section":"Tags","summary":"","title":"Meeting"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/scrum/","section":"Tags","summary":"","title":"Scrum"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/standup/","section":"Tags","summary":"","title":"Standup"},{"content":"Primo lunedì del progetto. Nuovo team, nuova metodologia, nuove speranze. Il PM propone lo standup quotidiano. Tutti annuiscono. \u0026ldquo;Quindici minuti, in piedi, tre domande. Semplice.\u0026rdquo;\nLa prima settimana funziona. Alle 9:15 si parte, alle 9:28 si è già alla scrivania. Ognuno dice il suo in due minuti, si segnalano i blocchi, ci si saluta. Efficienza pura.\nLa seconda settimana qualcuno alza la mano durante il giro: \u0026ldquo;Posso spiegare un attimo il problema che ho con l\u0026rsquo;integrazione?\u0026rdquo; Cinque minuti di discussione tecnica tra due persone. Gli altri sei stanno fermi ad ascoltare qualcosa che non li riguarda.\nLa terza settimana lo standup dura trentacinque minuti. Qualcuno porta il portatile. Qualcun altro si siede. Il giro delle tre domande è diventato una riunione di status con discussioni libere, demo improvvisate e dibattiti architetturali.\nAlla quarta settimana il team inizia a saltare lo standup. \u0026ldquo;Tanto ormai dura mezz\u0026rsquo;ora, non ho tempo.\u0026rdquo;\nHo visto questa sequenza almeno dieci volte nella mia carriera. Non è sfortuna. È un pattern.\n⏱️ Perché il vincolo dei 15 minuti non è negoziabile #Lo standup ha un solo scopo: sincronizzare il team. Non è una riunione di analisi. Non è un momento di problem-solving. Non è una sessione di design. È un punto di allineamento rapido.\nE il vincolo temporale è ciò che lo rende tale.\nQuando lo standup dura 15 minuti, succedono cose specifiche:\nLe persone si preparano prima della riunione, perché sanno che hanno due minuti I problemi vengono segnalati, non risolti. La risoluzione avviene dopo, tra le persone coinvolte Il team mantiene la percezione che lo standup è utile e rispettoso del loro tempo Nessuno arriva alla riunione pensando \u0026ldquo;ecco, un\u0026rsquo;altra mezz\u0026rsquo;ora buttata\u0026rdquo; Quando lo standup sfora i 20 minuti, il meccanismo si rompe:\nDurata Effetto sul team 10-15 min Focus alto, partecipazione attiva, percezione positiva 15-20 min Accettabile, ma qualcuno inizia a distrarsi 20-30 min Le persone non coinvolte nei thread lunghi si disconnettono mentalmente 30-45 min Il team percepisce lo standup come una perdita di tempo. Iniziano le assenze 45+ min Lo standup è morto. È diventato una riunione di status mascherata da pratica agile La cosa più pericolosa non è lo sforamento in sé. È che avviene gradualmente. Tre minuti in più oggi, cinque domani. Nessuno se ne accorge finché non è troppo tardi.\n❓ Le tre domande — e nient\u0026rsquo;altro #Lo standup classico si basa su tre domande:\nCosa ho fatto ieri? Cosa farò oggi? C\u0026rsquo;è qualcosa che mi blocca? Semplice. Ma la semplicità è traditrice, perché la tentazione di espandere è costante.\n\u0026ldquo;Cosa ho fatto ieri\u0026rdquo; non significa raccontare la giornata. Significa dire: \u0026ldquo;Ho chiuso la migrazione delle tabelle lookup\u0026rdquo; oppure \u0026ldquo;Ho lavorato sul bug #247, non l\u0026rsquo;ho ancora risolto.\u0026rdquo; Dieci secondi, non tre minuti.\n\u0026ldquo;Cosa farò oggi\u0026rdquo; non è un piano dettagliato. È una dichiarazione di intento: \u0026ldquo;Oggi finisco il bug #247 e comincio i test di integrazione.\u0026rdquo;\n\u0026ldquo;C\u0026rsquo;è qualcosa che mi blocca\u0026rdquo; è la domanda più importante. Perché qui emergono le dipendenze, i colli di bottiglia, i problemi che uno da solo non può risolvere. Ma — e questo è fondamentale — il blocco si segnala, non si risolve in diretta.\nQuando qualcuno dice \u0026ldquo;Sono bloccato perché non ho accesso all\u0026rsquo;ambiente di staging\u0026rdquo;, la risposta corretta non è una discussione di quindici minuti su chi deve dare l\u0026rsquo;accesso, come configurarlo e perché non funzionava ieri. La risposta corretta è: \u0026ldquo;Ok, ne parliamo dopo lo standup, io e te.\u0026rdquo;\nÈ questa disciplina che mantiene lo standup sotto i 15 minuti. Senza di essa, ogni blocco diventa una riunione nella riunione.\n💀 Quando lo standup muore #Ho identificato un elenco abbastanza preciso dei modi in cui uno standup può morire. Li elenco non per pessimismo, ma perché riconoscerli è l\u0026rsquo;unico modo per prevenirli.\nIl thread killer #Una persona racconta un problema tecnico complesso. Un\u0026rsquo;altra persona risponde. Parte un dialogo tra due, mentre sei persone stanno ferme. Il facilitatore non interviene perché \u0026ldquo;è un argomento importante\u0026rdquo;. Quindici minuti persi.\nIl demo improvvisato #\u0026ldquo;Aspettate, vi faccio vedere cosa ho fatto.\u0026rdquo; Condivisione schermo, navigazione nell\u0026rsquo;applicazione, spiegazione di dettagli UI. Interessante? Forse. Pertinente allo standup? No.\nIl manager che fa domande #Il PM o il team lead inizia a fare domande di approfondimento: \u0026ldquo;Ma quella feature è al 60% o al 70%? Quando prevedi di finire? Hai parlato con il cliente?\u0026rdquo; Lo standup si trasforma in un report individuale.\nL\u0026rsquo;assenza del facilitatore #Senza qualcuno che tenga il ritmo, lo standup diventa una conversazione libera. La conversazione libera è bellissima al bar, non alle 9:15 del mattino quando otto persone hanno da lavorare.\nIl portatile aperto #Quando le persone portano il laptop allo standup, il messaggio implicito è: \u0026ldquo;Questa riunione non merita la mia piena attenzione.\u0026rdquo; E hanno ragione — se lo standup dura 40 minuti, non la merita.\n🛠️ Come far funzionare uno standup — sul serio #Dopo vent\u0026rsquo;anni di progetti, la mia ricetta è questa. Non è elegante, non è da manuale, ma funziona.\n1. Timer visibile #Un timer sullo schermo condiviso (o un telefono appoggiato sul tavolo) che parte quando inizia lo standup. Tutti lo vedono. Quando segna 15 minuti, lo standup finisce. Punto.\nNon è autoritario. È un accordo di squadra. Il timer non è il nemico — è il guardiano del tempo di tutti.\n2. Facilitatore con il compito di tagliare #Serve una persona — a rotazione o fissa — il cui unico compito è dire: \u0026ldquo;Ok, questo argomento lo approfondiamo dopo. Prossimo.\u0026rdquo; Non è maleducazione. È rispetto per le sei persone che stanno aspettando.\nIl facilitatore migliore è quello che lo fa con naturalezza: \u0026ldquo;Interessante, ne parliamo subito dopo. Marco, tocca a te.\u0026rdquo;\n3. In piedi, davvero #Non è folklore. Stare in piedi ha un effetto psicologico concreto: le persone vogliono finire in fretta. Quando ti siedi, ti rilassi. Quando stai in piedi, tendi alla sintesi.\nSe il team è da remoto, il principio si traduce in: telecamere accese, niente multitasking. Il segnale deve essere: \u0026ldquo;Questi 15 minuti hanno la mia attenzione completa.\u0026rdquo;\n4. Niente portatili, niente condivisione schermo #Lo standup è verbale. Se qualcosa richiede una demo, un diagramma, una spiegazione visiva — non è roba da standup. È roba da un meeting separato, con le persone giuste.\n5. Parking lot #Ogni volta che emerge un argomento che merita approfondimento, il facilitatore lo scrive in una lista visibile — il \u0026ldquo;parking lot\u0026rdquo;. Dopo lo standup, le persone coinvolte si fermano e ne discutono. Gli altri vanno a lavorare.\nIl parking lot è lo strumento più sottovalutato nella gestione degli standup. Permette di dire \u0026ldquo;ne parliamo dopo\u0026rdquo; senza che l\u0026rsquo;argomento venga dimenticato.\n📊 Lo standup in numeri #Facciamo un calcolo che nessuno fa mai.\nUn team di 8 persone. Standup quotidiano. 220 giorni lavorativi all\u0026rsquo;anno.\nScenario Durata Ore/persona/anno Ore totali team/anno Standup da 15 minuti 15 min 55 ore 440 ore Standup da 30 minuti 30 min 110 ore 880 ore Standup da 45 minuti 45 min 165 ore 1.320 ore La differenza tra uno standup ben gestito e uno fuori controllo è 880 ore all\u0026rsquo;anno. Per un team di 8 persone. Sono 110 giornate lavorative. Quasi cinque mesi-uomo.\nE questo senza contare l\u0026rsquo;effetto indiretto: uno standup da 45 minuti non ruba solo 45 minuti. Ruba anche i 10-15 minuti di concentrazione che servono dopo per rientrare nel flusso di lavoro.\n🔄 Standup remoto vs in presenza #Dal 2020 gli standup sono spesso da remoto. Cambia il mezzo, ma i principi restano identici. Con alcune accortezze in più.\nIn remoto è peggio (se non stai attento) # La latenza audio crea sovrapposizioni che allungano i tempi Il multitasking è invisibile (ma reale) La mancanza di linguaggio corporeo rende più difficile per il facilitatore capire quando tagliare La condivisione schermo è a un click di distanza, e la tentazione di usarla è alta Come gestire lo standup remoto # Pratica Motivo Ordine di parola predefinito Evita il \u0026ldquo;chi parla?\u0026rdquo; e i silenzi imbarazzanti Telecamere accese Segnala presenza e attenzione Chat per il parking lot Cattura i temi in tempo reale senza interrompere Timer condiviso sullo schermo Stesso principio dello standup in presenza Mute per tutti tranne chi parla Elimina rumori di fondo e tentazioni di interrupt Il trucco più efficace che ho trovato per gli standup remoti è il giro a staffetta: ogni persona, dopo aver parlato, nomina la successiva. \u0026ldquo;Ho finito. Sara, a te.\u0026rdquo; Questo mantiene l\u0026rsquo;attenzione attiva e dà ritmo alla riunione.\n🎯 Lo standup è uno strumento, non un rituale #La cosa che mi ha sempre colpito è la facilità con cui lo standup diventa un rituale vuoto. Lo fai perché \u0026ldquo;si fa così\u0026rdquo;, perché \u0026ldquo;siamo agile\u0026rdquo;, perché \u0026ldquo;il framework lo prevede\u0026rdquo;. Ma nessuno si chiede più: sta funzionando?\nUno standup funziona quando il team lo percepisce come utile. Quando alle 9:15 le persone si presentano volentieri, dicono il loro in due minuti, ascoltano gli altri, e alle 9:30 sono alla scrivania sapendo esattamente cosa succede nel progetto.\nUno standup non funziona quando le persone lo percepiscono come un obbligo. Quando sospirano guardando l\u0026rsquo;orologio. Quando controllano il telefono. Quando pensano \u0026ldquo;potevo usare questa mezz\u0026rsquo;ora per lavorare.\u0026rdquo;\nLa differenza tra i due scenari è quasi sempre la stessa: il vincolo dei 15 minuti è rispettato o no.\nNon servono framework sofisticati. Non servono certificazioni. Serve un timer, un facilitatore con la spina dorsale, e la consapevolezza che il tempo delle persone ha un valore.\nQuindici minuti. Tre domande. Parking lot per il resto.\nTutto il resto è rumore.\nGlossario #Daily Standup — Riunione quotidiana di massimo 15 minuti in cui ogni membro del team risponde a tre domande: cosa ho fatto ieri, cosa farò oggi, cosa mi blocca.\nParking Lot — Lista visibile di argomenti emersi durante una riunione che meritano approfondimento ma vengono rinviati a dopo per rispettare il timebox.\nFacilitatore — Persona responsabile di guidare una riunione mantenendo il focus, rispettando il timebox e garantendo che tutti abbiano voce.\nTimeboxing — Tecnica di gestione del tempo che assegna un intervallo fisso e non negoziabile a un\u0026rsquo;attività, forzando la conclusione entro il limite stabilito.\nScrum — Framework agile per la gestione di progetti che organizza il lavoro in sprint a durata fissa, con ruoli definiti e cerimonie strutturate.\n","date":"27 gennaio 2026","permalink":"https://ivanluminaria.com/it/posts/project-management/standup-meeting-15-minuti/","section":"Database Strategy","summary":"\u003cp\u003ePrimo lunedì del progetto. Nuovo team, nuova metodologia, nuove speranze. Il PM propone lo standup quotidiano. Tutti annuiscono. \u0026ldquo;Quindici minuti, in piedi, tre domande. Semplice.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eLa prima settimana funziona. Alle 9:15 si parte, alle 9:28 si è già alla scrivania. Ognuno dice il suo in due minuti, si segnalano i blocchi, ci si saluta. Efficienza pura.\u003c/p\u003e\n\u003cp\u003eLa seconda settimana qualcuno alza la mano durante il giro: \u0026ldquo;Posso spiegare un attimo il problema che ho con l\u0026rsquo;integrazione?\u0026rdquo; Cinque minuti di discussione tecnica tra due persone. Gli altri sei stanno fermi ad ascoltare qualcosa che non li riguarda.\u003c/p\u003e","title":"Standup meeting: perché funzionano solo se durano 15 minuti"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/team-management/","section":"Tags","summary":"","title":"Team-Management"},{"content":"Mi è capitato più volte di entrare in un ambiente Oracle e trovare la stessa situazione: tutti gli utenti applicativi connessi come schema owner, con il ruolo DBA assegnato. Sviluppatori, applicazioni batch, tool di reportistica — tutti con gli stessi privilegi dell\u0026rsquo;utente che possiede le tabelle.\nQuando chiedi perché, la risposta è sempre una variante di: \u0026ldquo;Così funziona tutto senza problemi di permessi.\u0026rdquo;\nCerto. Funziona tutto. Fino al giorno in cui uno sviluppatore lancia un DROP TABLE sulla tabella sbagliata. O un batch di import fa un TRUNCATE su una tabella di produzione pensando di essere in ambiente di test. O qualcuno esegue un DELETE FROM clienti senza la clausola WHERE.\nQuel giorno il problema non sono più i permessi. È che non hai idea di chi abbia fatto cosa, e non hai nessuno strumento per impedire che succeda di nuovo.\nIl contesto: un classico che si ripete #Il cliente era una media azienda con un\u0026rsquo;applicazione gestionale su Oracle 19c. Circa venti utenti tra sviluppatori, applicativi e operatori. Lo schema applicativo — chiamiamolo APP_OWNER — conteneva circa 300 tabelle, una sessantina di viste e qualche decina di procedure PL/SQL.\nIl problema era semplice da descrivere:\nTutti si collegavano come APP_OWNER APP_OWNER aveva il ruolo DBA Nessun audit configurato Nessuna separazione tra chi legge e chi scrive Le password erano condivise via email Non era negligenza. Era inerzia. Il sistema era cresciuto così nel corso degli anni, e nessuno si era mai fermato a ripensare il modello. Funzionava, e questo bastava.\nFino a quando un operatore ha cancellato per errore i dati di fatturazione di un intero trimestre. Nessun log, nessuna traccia, nessun colpevole identificabile. Solo un backup di due giorni prima e un buco nei dati che ha richiesto settimane di lavoro per essere colmato.\nCome funziona la sicurezza in Oracle: il modello #Prima di raccontare cosa ho fatto, serve capire come Oracle struttura la sicurezza. Il modello è diverso da PostgreSQL e da MySQL, e le differenze non sono cosmetiche.\nUtente e schema: la stessa cosa (quasi) #In Oracle, creare un utente significa creare uno schema. Non sono due concetti separati: l\u0026rsquo;utente APP_OWNER è anche lo schema APP_OWNER, e gli oggetti creati da quell\u0026rsquo;utente vivono in quello schema.\nCREATE USER app_read IDENTIFIED BY \u0026#34;PasswordSicura#2026\u0026#34; DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA 0 ON users; La QUOTA 0 è intenzionale: questo utente non deve creare oggetti. È un consumatore, non un proprietario.\nPrivilegi di sistema vs privilegi di oggetto #Oracle distingue nettamente tra:\nSystem privileges: operazioni globali come CREATE TABLE, CREATE SESSION, ALTER SYSTEM Object privileges: operazioni su oggetti specifici come SELECT ON app_owner.clienti, EXECUTE ON app_owner.pkg_fatture Il ruolo DBA include oltre 200 system privilege. Assegnarlo a un utente applicativo è come dare le chiavi dell\u0026rsquo;intero palazzo a chi deve solo entrare in una stanza.\nI ruoli: predefiniti e custom #Oracle offre ruoli predefiniti (CONNECT, RESOURCE, DBA) e permette di crearne di custom. I ruoli predefiniti hanno un problema storico: CONNECT e RESOURCE includevano privilegi eccessivi nelle versioni più vecchie. Da Oracle 12c in poi sono stati ridimensionati, ma l\u0026rsquo;abitudine di assegnarli senza pensarci è dura a morire.\nLa strada giusta è creare ruoli custom calibrati sulle reali necessità.\nL\u0026rsquo;implementazione: tre ruoli, zero ambiguità #Ho progettato tre ruoli: lettura, scrittura e amministrazione applicativa.\n1. Ruolo di sola lettura #CREATE ROLE app_read_role; -- Privilegi sulle tabelle GRANT SELECT ON app_owner.clienti TO app_read_role; GRANT SELECT ON app_owner.ordini TO app_read_role; GRANT SELECT ON app_owner.fatture TO app_read_role; GRANT SELECT ON app_owner.prodotti TO app_read_role; GRANT SELECT ON app_owner.movimenti TO app_read_role; -- Privilegi sulle viste GRANT SELECT ON app_owner.v_report_vendite TO app_read_role; GRANT SELECT ON app_owner.v_stato_ordini TO app_read_role; In un ambiente con 300 tabelle non le elenchi una per una a mano. Ho usato un blocco PL/SQL per generare i grant:\nBEGIN FOR t IN (SELECT table_name FROM dba_tables WHERE owner = \u0026#39;APP_OWNER\u0026#39;) LOOP EXECUTE IMMEDIATE \u0026#39;GRANT SELECT ON app_owner.\u0026#39; || t.table_name || \u0026#39; TO app_read_role\u0026#39;; END LOOP; END; / Semplice, ripetibile, e soprattutto: documentato. Perché tra sei mesi qualcuno dovrà capire cosa è stato fatto e perché.\n2. Ruolo di lettura e scrittura #CREATE ROLE app_write_role; -- Eredita tutto dal ruolo di lettura GRANT app_read_role TO app_write_role; -- Aggiunge DML sulle tabelle operative GRANT INSERT, UPDATE, DELETE ON app_owner.ordini TO app_write_role; GRANT INSERT, UPDATE, DELETE ON app_owner.movimenti TO app_write_role; GRANT INSERT, UPDATE ON app_owner.clienti TO app_write_role; -- Permesso di esecuzione sulle procedure applicative GRANT EXECUTE ON app_owner.pkg_ordini TO app_write_role; GRANT EXECUTE ON app_owner.pkg_fatture TO app_write_role; Nota: niente DELETE sulla tabella clienti. Non perché sia tecnicamente impossibile, ma perché il processo applicativo prevede una disattivazione, non una cancellazione. Il privilegio riflette il processo, non la comodità.\n3. Ruolo di amministrazione applicativa #CREATE ROLE app_admin_role; -- Eredita il ruolo di scrittura GRANT app_write_role TO app_admin_role; -- Aggiunge DDL controllato GRANT CREATE VIEW TO app_admin_role; GRANT CREATE PROCEDURE TO app_admin_role; GRANT CREATE SYNONYM TO app_admin_role; -- Può gestire le tabelle di configurazione GRANT INSERT, UPDATE, DELETE ON app_owner.parametri TO app_admin_role; GRANT INSERT, UPDATE, DELETE ON app_owner.lookup_tipi TO app_admin_role; Niente CREATE TABLE, niente DROP ANY, niente ALTER SYSTEM. L\u0026rsquo;admin applicativo gestisce la logica, non la struttura fisica.\nCreazione degli utenti e assegnazione #-- Utente per i report (sola lettura) CREATE USER srv_report IDENTIFIED BY \u0026#34;RptSecure#2026\u0026#34; DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA 0 ON users; GRANT CREATE SESSION TO srv_report; GRANT app_read_role TO srv_report; -- Utente applicativo (lettura e scrittura) CREATE USER srv_app IDENTIFIED BY \u0026#34;AppSecure#2026\u0026#34; DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA 0 ON users; GRANT CREATE SESSION TO srv_app; GRANT app_write_role TO srv_app; -- DBA applicativo (amministrazione) CREATE USER dba_app IDENTIFIED BY \u0026#34;DbaSecure#2026\u0026#34; DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA 10M ON users; GRANT CREATE SESSION TO dba_app; GRANT app_admin_role TO dba_app; Ogni utente ha una password propria, un ruolo specifico e una quota disco coerente con il suo scopo. srv_report non ha quota perché non deve creare nulla. dba_app ha 10 MB perché deve poter creare viste e procedure.\nRevoca del ruolo DBA #Il passo più delicato: togliere il DBA a APP_OWNER.\nREVOKE DBA FROM app_owner; Una riga. Ma prima di eseguirla, ho verificato che APP_OWNER avesse ancora i privilegi necessari per possedere i propri oggetti:\nSELECT privilege FROM dba_sys_privs WHERE grantee = \u0026#39;APP_OWNER\u0026#39;; SELECT granted_role FROM dba_role_privs WHERE grantee = \u0026#39;APP_OWNER\u0026#39;; E ho assegnato solo i privilegi strettamente necessari:\nGRANT CREATE SESSION TO app_owner; GRANT CREATE TABLE TO app_owner; GRANT CREATE VIEW TO app_owner; GRANT CREATE PROCEDURE TO app_owner; GRANT CREATE SEQUENCE TO app_owner; GRANT UNLIMITED TABLESPACE TO app_owner; APP_OWNER rimane il proprietario degli oggetti, ma non ha più il potere di fare qualsiasi cosa sul database. È un proprietario, non un dio.\nAudit: sapere chi fa cosa #Avere i ruoli giusti non basta. Serve sapere chi fa cosa, soprattutto sulle operazioni critiche.\nOracle dalla versione 12c offre Unified Audit, che sostituisce il vecchio audit tradizionale con un sistema centralizzato.\n-- Audit su operazioni DDL critiche CREATE AUDIT POLICY pol_ddl_critico ACTIONS CREATE TABLE, DROP TABLE, ALTER TABLE, TRUNCATE TABLE, CREATE USER, DROP USER, ALTER USER, GRANT, REVOKE; ALTER AUDIT POLICY pol_ddl_critico ENABLE; -- Audit su accessi sensibili CREATE AUDIT POLICY pol_accesso_dati ACTIONS SELECT ON app_owner.clienti, DELETE ON app_owner.fatture, UPDATE ON app_owner.fatture; ALTER AUDIT POLICY pol_accesso_dati ENABLE; -- Audit sui login falliti CREATE AUDIT POLICY pol_login_falliti ACTIONS LOGON; ALTER AUDIT POLICY pol_login_falliti ENABLE WHENEVER NOT SUCCESSFUL; Per verificare cosa viene registrato:\nSELECT * FROM unified_audit_trail WHERE event_timestamp \u0026gt; SYSDATE - 7 ORDER BY event_timestamp DESC; L\u0026rsquo;audit non è paranoia. È l\u0026rsquo;unico modo per rispondere alla domanda \u0026ldquo;chi ha fatto cosa?\u0026rdquo; senza dover andare a intuizione.\nIl confronto con PostgreSQL e MySQL #Questo articolo è il terzo di una serie sulla gestione della sicurezza nei database relazionali. I primi due coprono PostgreSQL e MySQL.\nLe differenze tra i tre sistemi sono sostanziali:\nAspetto Oracle PostgreSQL MySQL Utente = schema? Sì No (indipendenti) Sì (database separati) Modello ruoli Ruoli predefiniti + custom Tutto è un ROLE Ruoli da MySQL 8.0 Identità Nome utente Nome utente Coppia utente@host Audit nativo Unified Audit (12c+) pgAudit (estensione) Audit plugin Privilegi granulari System + Object Database/Schema/Object Global/DB/Table/Column GRANT ALL Esiste ma pericoloso Esiste, sconsigliato Esiste, sconsigliato In PostgreSQL tutto è un ROLE, e la semplicità del modello è il suo punto di forza. In MySQL l\u0026rsquo;identità è legata all\u0026rsquo;host di origine, il che aggiunge un livello di complessità (e di sicurezza) che gli altri non hanno. In Oracle il modello è il più ricco e il più granulare, ma anche il più facile da configurare male per eccesso di opzioni.\nIl principio resta lo stesso ovunque: dai a ciascuno solo quello che gli serve, non un privilegio in più.\nCosa è cambiato dopo #Il passaggio è stato graduale — due settimane per il rollout completo, con test su ogni applicativo e procedura. Qualche script ha smesso di funzionare perché dava per scontato di avere privilegi che non gli spettavano. Ogni errore era in realtà un problema nascosto che prima era invisibile.\nIl risultato:\n20 utenti nominali al posto di un unico schema condiviso 3 ruoli custom al posto del ruolo DBA Audit attivo su DDL e operazioni sensibili Zero incidenti di cancellazione accidentale nei mesi successivi Il cliente non ha notato miglioramenti nelle performance. Non era quello l\u0026rsquo;obiettivo. Ha notato che quando qualcuno sbagliava, il danno era contenuto e tracciabile. E questo, in un ambiente di produzione, vale più di qualsiasi ottimizzazione.\nConclusione #GRANT ALL PRIVILEGES e il ruolo DBA sono scorciatoie. Funzionano nel senso che eliminano gli errori di permesso. Ma eliminano anche qualsiasi protezione.\nLa sicurezza in Oracle non è questione di strumenti — gli strumenti ci sono, e sono potenti. È questione di progettazione: decidere chi può fare cosa, documentarlo, implementarlo e poi verificare che funzioni.\nNon è il lavoro più glamour del mondo. Ma è quello che fa la differenza tra un database che sopravvive e uno che è davvero sotto controllo.\nGlossario #System Privilege — Privilegio Oracle che autorizza operazioni globali sul database come CREATE TABLE, CREATE SESSION o ALTER SYSTEM, indipendenti da qualsiasi oggetto specifico.\nObject Privilege — Privilegio Oracle che autorizza operazioni su un oggetto specifico del database come SELECT, INSERT o EXECUTE su una tabella, vista o procedura.\nREVOKE — Comando SQL per rimuovere privilegi o ruoli precedentemente assegnati a un utente o ruolo, complementare al comando GRANT.\nUnified Audit — Sistema di audit centralizzato introdotto in Oracle 12c che unifica tutti i tipi di audit in un\u0026rsquo;unica infrastruttura, sostituendo il vecchio audit tradizionale.\nLeast Privilege — Principio di sicurezza che prevede l\u0026rsquo;assegnazione a ogni utente solo dei permessi strettamente necessari per svolgere la propria funzione.\n","date":"27 gennaio 2026","permalink":"https://ivanluminaria.com/it/posts/oracle/oracle-roles-privileges/","section":"Database Strategy","summary":"\u003cp\u003eMi è capitato più volte di entrare in un ambiente Oracle e trovare la stessa situazione: tutti gli utenti applicativi connessi come schema owner, con il ruolo DBA assegnato. Sviluppatori, applicazioni batch, tool di reportistica — tutti con gli stessi privilegi dell\u0026rsquo;utente che possiede le tabelle.\u003c/p\u003e\n\u003cp\u003eQuando chiedi perché, la risposta è sempre una variante di: \u0026ldquo;Così funziona tutto senza problemi di permessi.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eCerto. Funziona tutto. Fino al giorno in cui uno sviluppatore lancia un \u003ccode\u003eDROP TABLE\u003c/code\u003e sulla tabella sbagliata. O un batch di import fa un \u003ccode\u003eTRUNCATE\u003c/code\u003e su una tabella di produzione pensando di essere in ambiente di test. O qualcuno esegue un \u003ccode\u003eDELETE FROM clienti\u003c/code\u003e senza la clausola \u003ccode\u003eWHERE\u003c/code\u003e.\u003c/p\u003e","title":"Utenti, ruoli e privilegi in Oracle: perché GRANT ALL non è mai la risposta"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/dimensional-modeling/","section":"Tags","summary":"","title":"Dimensional-Modeling"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/etl/","section":"Tags","summary":"","title":"Etl"},{"content":"Tre livelli. Top Group, Group, Client. Sembra una struttura banale — il tipo di gerarchia che disegni su una lavagna in cinque minuti e che qualsiasi tool di BI dovrebbe gestire senza problemi.\nPoi scopri che non tutti i clienti hanno un gruppo. E che non tutti i gruppi hanno un top group. E che i report di aggregazione che il business ti chiede — fatturato per top group, numero clienti per gruppo, drill-down dal vertice alla foglia — producono risultati sbagliati o incompleti perché la gerarchia ha dei buchi.\nIn gergo tecnico si chiama ragged hierarchy : una gerarchia in cui non tutti i rami raggiungono la stessa profondità. Nel mondo reale si chiama \u0026ldquo;il problema che nessuno vede finché non apre il report e i numeri non tornano.\u0026rdquo;\nIl cliente e il modello originale #Il progetto era un data warehouse per un\u0026rsquo;azienda nel settore energy — distribuzione gas e servizi correlati. Il sistema sorgente gestiva un\u0026rsquo;anagrafica clienti con una struttura gerarchica: i clienti potevano essere raggruppati sotto un\u0026rsquo;entità commerciale (il Group), e i gruppi potevano a loro volta appartenere a un\u0026rsquo;entità superiore (il Top Group).\nIl modello nella sorgente era una singola tabella con i riferimenti gerarchici:\nCREATE TABLE stg_clienti ( client_id NUMBER(10) NOT NULL, client_name VARCHAR2(100) NOT NULL, group_id NUMBER(10), group_name VARCHAR2(100), top_group_id NUMBER(10), top_group_name VARCHAR2(100), revenue NUMBER(15,2), region VARCHAR2(50), CONSTRAINT pk_stg_clienti PRIMARY KEY (client_id) ); Ecco un campione dei dati:\nINSERT INTO stg_clienti VALUES (1001, \u0026#39;Rossi Energia Srl\u0026#39;, 10, \u0026#39;Consorzio Nord\u0026#39;, 100, \u0026#39;Holding Nazionale\u0026#39;, 125000.00, \u0026#39;Lombardia\u0026#39;); INSERT INTO stg_clienti VALUES (1002, \u0026#39;Bianchi Gas SpA\u0026#39;, 10, \u0026#39;Consorzio Nord\u0026#39;, 100, \u0026#39;Holding Nazionale\u0026#39;, 89000.00, \u0026#39;Piemonte\u0026#39;); INSERT INTO stg_clienti VALUES (1003, \u0026#39;Verdi Distribuzione\u0026#39;, 20, \u0026#39;Gruppo Centro\u0026#39;, 100, \u0026#39;Holding Nazionale\u0026#39;, 67000.00, \u0026#39;Toscana\u0026#39;); INSERT INTO stg_clienti VALUES (1004, \u0026#39;Neri Servizi\u0026#39;, 20, \u0026#39;Gruppo Centro\u0026#39;, NULL, NULL, 45000.00, \u0026#39;Lazio\u0026#39;); INSERT INTO stg_clienti VALUES (1005, \u0026#39;Gialli Utilities\u0026#39;, NULL, NULL, NULL, NULL, 38000.00, \u0026#39;Sicilia\u0026#39;); INSERT INTO stg_clienti VALUES (1006, \u0026#39;Blu Energia\u0026#39;, NULL, NULL, NULL, NULL, 52000.00, \u0026#39;Sardegna\u0026#39;); INSERT INTO stg_clienti VALUES (1007, \u0026#39;Viola Gas Srl\u0026#39;, 30, \u0026#39;Rete Sud\u0026#39;, NULL, NULL, 71000.00, \u0026#39;Campania\u0026#39;); INSERT INTO stg_clienti VALUES (1008, \u0026#39;Arancio Distribuzione\u0026#39;, 30, \u0026#39;Rete Sud\u0026#39;, NULL, NULL, 33000.00, \u0026#39;Calabria\u0026#39;); Guardate i dati con attenzione. Ci sono quattro situazioni diverse:\nClient 1001, 1002, 1003: gerarchia completa — Client → Group → Top Group Client 1004: ha un Group ma il Group non ha un Top Group Client 1005, 1006: nessun Group, nessun Top Group — clienti diretti Client 1007, 1008: hanno un Group (Rete Sud) ma il Group non ha un Top Group Questa è una ragged hierarchy. Tre livelli sulla carta, ma nella realtà i rami hanno profondità diverse.\nIl problema: i report non tornano #Il business chiedeva un report semplice: fatturato aggregato per Top Group, con possibilità di drill-down per Group e poi per Client. Una richiesta ragionevole — il tipo di cosa che ti aspetti da qualsiasi DWH.\nLa query più naturale:\nSELECT top_group_name, group_name, COUNT(*) AS num_clienti, SUM(revenue) AS fatturato_totale FROM stg_clienti GROUP BY top_group_name, group_name ORDER BY top_group_name, group_name; Il risultato:\nTOP_GROUP_NAME GROUP_NAME NUM_CLIENTI FATTURATO_TOTALE ------------------ ---------------- ----------- ---------------- Holding Nazionale Consorzio Nord 2 214000.00 Holding Nazionale Gruppo Centro 1 67000.00 (null) Gruppo Centro 1 45000.00 (null) Rete Sud 2 104000.00 (null) (null) 2 90000.00 Cinque righe. E almeno tre problemi.\nIl Gruppo Centro appare due volte: una sotto \u0026ldquo;Holding Nazionale\u0026rdquo; (il client 1003 che ha il top group) e una sotto NULL (il client 1004 il cui top group è NULL). Lo stesso gruppo, spaccato su due righe, con totali separati. Chiunque guardi questo report penserà che Gruppo Centro abbia 67K di fatturato sotto la holding e 45K da qualche altra parte. In realtà è un unico gruppo con 112K totali.\nI clienti diretti (Gialli Utilities e Blu Energia) finiscono in una riga con due NULL. Il management non sa cosa farsene di una riga senza nome.\nIl totale per Top Group è sbagliato perché mancano le righe con NULL. Se sommi solo le righe con un top group, perdi 239K di fatturato — il 30% del totale.\nL\u0026rsquo;approccio classico: COALESCE e preghiere #La prima reazione, quella che vedo fare nel 90% dei casi, è aggiungere `COALESCE` nella query:\nSELECT COALESCE(top_group_name, group_name, client_name) AS top_group_name, COALESCE(group_name, client_name) AS group_name, client_name, revenue FROM stg_clienti; Funziona? In un certo senso sì — riempie i buchi. Ma introduce problemi nuovi.\nIl client \u0026ldquo;Gialli Utilities\u0026rdquo; ora appare come Top Group, Group e Client contemporaneamente. Se il business vuole contare quanti Top Group ci sono, il numero è gonfiato. Se vuole filtrare per \u0026ldquo;veri\u0026rdquo; top group, non ha modo di distinguerli dai clienti promossi a top group dalla COALESCE.\nE questo è il caso semplice, con tre livelli. Ho visto gerarchie a cinque livelli gestite con catene di COALESCE nidificati, CASE WHEN multipli, e una logica di report talmente contorta che nessuno osava più toccarla. Ogni nuova richiesta del business richiedeva una modifica a cascata su tutte le query.\nIl problema di fondo è che la COALESCE è un cerotto applicato nel layer di presentazione. Non risolve il problema strutturale: la gerarchia è incompleta e il modello dimensionale non lo sa.\nLa soluzione: self-parenting #Il principio è semplice: chi non ha un padre diventa padre di sé stesso. Questa tecnica si chiama self-parenting .\nUn Client senza Group? Quel client diventa il proprio Group. Un Group senza Top Group? Quel group diventa il proprio Top Group. In questo modo la gerarchia è sempre completa a tre livelli, senza buchi, senza NULL.\nNon è un trucco. È una tecnica standard nel dimensional modeling, descritta da Kimball e usata in produzione da decenni. L\u0026rsquo;idea è che la dimensione gerarchica nel DWH deve essere bilanciata: ogni record deve avere un valore valido per ogni livello della gerarchia. Se la sorgente non lo garantisce, lo garantisce l\u0026rsquo;ETL .\nLa tabella dimensionale #CREATE TABLE dim_client_hierarchy ( client_key NUMBER(10) NOT NULL, client_id NUMBER(10) NOT NULL, client_name VARCHAR2(100) NOT NULL, group_id NUMBER(10) NOT NULL, group_name VARCHAR2(100) NOT NULL, top_group_id NUMBER(10) NOT NULL, top_group_name VARCHAR2(100) NOT NULL, region VARCHAR2(50), is_direct_client CHAR(1) DEFAULT \u0026#39;N\u0026#39;, is_standalone_group CHAR(1) DEFAULT \u0026#39;N\u0026#39;, CONSTRAINT pk_dim_client_hier PRIMARY KEY (client_key) ); Notate due cose. Primo: nessuna colonna è nullable. Group e Top Group sono NOT NULL. Secondo: ho aggiunto due flag — is_direct_client e is_standalone_group — che permettono di distinguere i record bilanciati artificialmente da quelli che hanno una gerarchia naturale. Questo è importante: il business deve poter filtrare i \u0026ldquo;veri\u0026rdquo; top group dai clienti promossi.\nLa logica ETL #INSERT INTO dim_client_hierarchy ( client_key, client_id, client_name, group_id, group_name, top_group_id, top_group_name, region, is_direct_client, is_standalone_group ) SELECT client_id AS client_key, client_id, client_name, -- Se non ha un group, il client diventa group di sé stesso COALESCE(group_id, client_id) AS group_id, COALESCE(group_name, client_name) AS group_name, -- Se non ha un top group, il group (o il client) diventa top group di sé stesso COALESCE(top_group_id, group_id, client_id) AS top_group_id, COALESCE(top_group_name, group_name, client_name) AS top_group_name, region, CASE WHEN group_id IS NULL THEN \u0026#39;Y\u0026#39; ELSE \u0026#39;N\u0026#39; END AS is_direct_client, CASE WHEN group_id IS NOT NULL AND top_group_id IS NULL THEN \u0026#39;Y\u0026#39; ELSE \u0026#39;N\u0026#39; END AS is_standalone_group FROM stg_clienti; Guardate la cascata di COALESCE nella trasformazione. La logica è:\ngroup_id: se il client ha un group, usa quello; altrimenti usa il client stesso top_group_id: se c\u0026rsquo;è un top group, usa quello; se non c\u0026rsquo;è ma c\u0026rsquo;è un group, usa il group; se non c\u0026rsquo;è neanche il group, usa il client Ogni livello \u0026ldquo;mancante\u0026rdquo; viene riempito dal livello immediatamente inferiore. Il risultato è una gerarchia sempre completa.\nIl risultato dopo il bilanciamento #SELECT client_key, client_name, group_name, top_group_name, is_direct_client, is_standalone_group FROM dim_client_hierarchy ORDER BY top_group_id, group_id, client_id; KEY CLIENT_NAME GROUP_NAME TOP_GROUP_NAME DIRECT STANDALONE ---- -------------------- ---------------- ------------------ ------ ---------- 1001 Rossi Energia Srl Consorzio Nord Holding Nazionale N N 1002 Bianchi Gas SpA Consorzio Nord Holding Nazionale N N 1003 Verdi Distribuzione Gruppo Centro Holding Nazionale N N 1004 Neri Servizi Gruppo Centro Gruppo Centro N Y 1007 Viola Gas Srl Rete Sud Rete Sud N Y 1008 Arancio Distribuzione Rete Sud Rete Sud N Y 1005 Gialli Utilities Gialli Utilities Gialli Utilities Y N 1006 Blu Energia Blu Energia Blu Energia Y N Otto righe, zero NULL. Ogni client ha un group e un top group. I flag dicono la verità: Gialli e Blu sono clienti diretti (self-parented a tutti i livelli), Gruppo Centro e Rete Sud sono gruppi standalone (self-parented al livello top group).\nI report dopo il bilanciamento #La stessa query di aggregazione che prima produceva risultati spezzati:\nSELECT top_group_name, group_name, COUNT(*) AS num_clienti, SUM(f.revenue) AS fatturato_totale FROM dim_client_hierarchy d JOIN stg_clienti f ON d.client_id = f.client_id GROUP BY top_group_name, group_name ORDER BY top_group_name, group_name; TOP_GROUP_NAME GROUP_NAME NUM_CLIENTI FATTURATO_TOTALE ------------------ ------------------ ----------- ---------------- Blu Energia Blu Energia 1 52000.00 Gialli Utilities Gialli Utilities 1 38000.00 Gruppo Centro Gruppo Centro 1 45000.00 Holding Nazionale Consorzio Nord 2 214000.00 Holding Nazionale Gruppo Centro 1 67000.00 Rete Sud Rete Sud 2 104000.00 Nessun NULL. Ogni riga ha un top group e un group identificabili. I totali tornano.\nE se il business vuole solo i \u0026ldquo;veri\u0026rdquo; top group, escludendo i clienti promossi:\nSELECT top_group_name, COUNT(*) AS num_clienti, SUM(f.revenue) AS fatturato_totale FROM dim_client_hierarchy d JOIN stg_clienti f ON d.client_id = f.client_id WHERE d.is_direct_client = \u0026#39;N\u0026#39; AND d.is_standalone_group = \u0026#39;N\u0026#39; GROUP BY top_group_name ORDER BY fatturato_totale DESC; TOP_GROUP_NAME NUM_CLIENTI FATTURATO_TOTALE ------------------ ----------- ---------------- Holding Nazionale 3 281000.00 I flag rendono tutto filtrabile. Nessuna logica condizionale nel report, nessun CASE WHEN, nessuna COALESCE. Il modello dimensionale contiene già tutta l\u0026rsquo;informazione necessaria.\nIl drill-down completo #Il vero test di una gerarchia bilanciata è il drill-down: dal livello più alto al più basso, senza sorprese.\n-- Livello 1: totale per Top Group SELECT top_group_name, COUNT(DISTINCT group_id) AS num_gruppi, COUNT(*) AS num_clienti, SUM(f.revenue) AS fatturato FROM dim_client_hierarchy d JOIN stg_clienti f ON d.client_id = f.client_id GROUP BY top_group_name ORDER BY fatturato DESC; TOP_GROUP_NAME NUM_GRUPPI NUM_CLIENTI FATTURATO ------------------ ---------- ----------- ---------- Holding Nazionale 2 3 281000.00 Rete Sud 1 2 104000.00 Blu Energia 1 1 52000.00 Gruppo Centro 1 1 45000.00 Gialli Utilities 1 1 38000.00 -- Livello 2: drill-down dentro \u0026#34;Holding Nazionale\u0026#34; SELECT group_name, COUNT(*) AS num_clienti, SUM(f.revenue) AS fatturato FROM dim_client_hierarchy d JOIN stg_clienti f ON d.client_id = f.client_id WHERE d.top_group_name = \u0026#39;Holding Nazionale\u0026#39; GROUP BY group_name ORDER BY fatturato DESC; GROUP_NAME NUM_CLIENTI FATTURATO ---------------- ----------- ---------- Consorzio Nord 2 214000.00 Gruppo Centro 1 67000.00 -- Livello 3: drill-down dentro \u0026#34;Consorzio Nord\u0026#34; SELECT client_name, f.revenue FROM dim_client_hierarchy d JOIN stg_clienti f ON d.client_id = f.client_id WHERE d.group_name = \u0026#39;Consorzio Nord\u0026#39; ORDER BY f.revenue DESC; CLIENT_NAME REVENUE ------------------- ---------- Rossi Energia Srl 125000.00 Bianchi Gas SpA 89000.00 Tre livelli di drill-down, zero NULL, zero logica condizionale. La gerarchia è bilanciata e i numeri tornano a ogni livello.\nPerché non basta la COALESCE nel report #Qualcuno potrebbe obiettare: \u0026ldquo;Ma la COALESCE nel report fa la stessa cosa, senza bisogno di modificare il modello.\u0026rdquo;\nNo. Fa qualcosa di simile, ma con tre differenze fondamentali.\nPrimo: la COALESCE va ripetuta ovunque. Ogni query, ogni report, ogni dashboard, ogni estrazione. Se hai venti report che usano la gerarchia, devi ricordarti di applicare la COALESCE in tutti e venti. E quando arriva il ventunesimo, devi ricordarti di nuovo. Il self-parenting nel modello dimensionale lo fai una volta nell\u0026rsquo;ETL e basta.\nSecondo: la COALESCE non distingue. Non sai se \u0026ldquo;Gialli Utilities\u0026rdquo; nel campo top_group è un vero top group o un client promosso. Con i flag nel modello dimensionale hai l\u0026rsquo;informazione per filtrare. Senza flag, il business è cieco.\nTerzo: le performance. Un GROUP BY con COALESCE su colonne nullable è meno efficiente di un GROUP BY su colonne NOT NULL. L\u0026rsquo;optimizer di Oracle gestisce meglio le colonne con vincoli NOT NULL — può eliminare controlli sui NULL, usare indici in modo più aggressivo, e produrre piani di esecuzione più semplici. Su una tabella dimensionale con milioni di righe, la differenza si vede.\nQuando usare il self-parenting (e quando no) #Il self-parenting funziona bene quando:\nLa gerarchia ha un numero fisso di livelli (tipicamente 2-5) Il caso d\u0026rsquo;uso principale è l\u0026rsquo;aggregazione e il drill-down nei report Il modello è un data warehouse o un cubo OLAP I livelli mancanti sono l\u0026rsquo;eccezione, non la regola Non funziona bene quando:\nLa gerarchia è ricorsiva con profondità variabile (es. organigrammi aziendali a N livelli) Serve navigare il grafo delle relazioni (es. reti sociali, supply chain) Il modello è OLTP e il self-parenting creerebbe ambiguità nelle logiche applicative I livelli della gerarchia cambiano frequentemente nel tempo Per le gerarchie ricorsive a profondità variabile, l\u0026rsquo;approccio corretto è diverso: tabelle di bridge, closure table o modelli parent-child con CTE ricorsive. Sono strumenti potenti ma risolvono un problema diverso.\nIl self-parenting risolve un problema specifico — gerarchie a livelli fissi con rami incompleti — e lo risolve nel modo più semplice possibile: bilanciando la struttura a monte, nel modello, anziché a valle, nei report.\nLa regola che mi guida #Ho progettato decine di dimensioni gerarchiche in vent\u0026rsquo;anni di data warehouse. La regola che mi porto dietro è sempre la stessa:\nSe il report ha bisogno di logica condizionale per gestire la gerarchia, il problema è nel modello, non nel report.\nUn report dovrebbe fare GROUP BY e JOIN. Se deve anche decidere come gestire i livelli mancanti, sta facendo il lavoro dell\u0026rsquo;ETL. E un report che fa il lavoro dell\u0026rsquo;ETL è un report che prima o poi si rompe.\nIl self-parenting non è elegante. Non è sofisticato. È una soluzione che un informatico appena laureato potrebbe trovare brutta. Ma funziona, è manutenibile, e trasforma un problema che infesta ogni singolo report in un problema che si risolve una volta sola, in un punto solo, e non torna più.\nA volte la soluzione migliore è la più semplice. Questa è una di quelle volte.\nGlossario #COALESCE — Funzione SQL che restituisce il primo valore non NULL da una lista di espressioni. Spesso usata come workaround per le gerarchie incomplete nei report, ma non risolve il problema strutturale nel modello dimensionale.\nDrill-down — Navigazione nei report dal livello aggregato al livello di dettaglio (es. da Top Group a Group a Client). Richiede una gerarchia completa e bilanciata per funzionare correttamente senza NULL o righe mancanti.\nOLAP — Online Analytical Processing — elaborazione orientata all\u0026rsquo;analisi multidimensionale dei dati, tipica dei data warehouse e dei cubi di analisi. Contrapposta all\u0026rsquo;OLTP (Online Transaction Processing) dei sistemi transazionali.\nRagged hierarchy — Gerarchia in cui non tutti i rami raggiungono la stessa profondità: alcuni livelli intermedi sono assenti. Tipica nelle anagrafiche clienti, prodotti e strutture organizzative dove non tutte le entità hanno la stessa struttura gerarchica.\nSelf-parenting — Tecnica di bilanciamento delle gerarchie sbilanciate: chi non ha un padre diventa padre di sé stesso. Il livello mancante viene riempito con i dati del livello inferiore, eliminando i NULL dalla dimensione e garantendo un drill-down corretto.\n","date":"20 gennaio 2026","permalink":"https://ivanluminaria.com/it/posts/data-warehouse/ragged-hierarchies/","section":"Database Strategy","summary":"\u003cp\u003eTre livelli. Top Group, Group, Client. Sembra una struttura banale — il tipo di gerarchia che disegni su una lavagna in cinque minuti e che qualsiasi tool di BI dovrebbe gestire senza problemi.\u003c/p\u003e\n\u003cp\u003ePoi scopri che non tutti i clienti hanno un gruppo. E che non tutti i gruppi hanno un top group. E che i report di aggregazione che il business ti chiede — fatturato per top group, numero clienti per gruppo, \u003cspan class=\"glossary-tip\" tabindex=\"0\" data-glossary-desc=\"Navigazione nei report dal livello aggregato al livello di dettaglio, tipica dell\u0026amp;#39;analisi OLAP e dei data warehouse.\" data-glossary-url=\"/it/glossary/drill-down/\" data-glossary-more=\"Leggi di più →\"\u003edrill-down\u003c/span\u003e\n dal vertice alla foglia — producono risultati sbagliati o incompleti perché la gerarchia ha dei buchi.\u003c/p\u003e","title":"Gerarchie sbilanciate: quando il cliente non ha un padre e il gruppo non ha un nonno"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/hierarchies/","section":"Tags","summary":"","title":"Hierarchies"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/olap/","section":"Tags","summary":"","title":"Olap"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/reporting/","section":"Tags","summary":"","title":"Reporting"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/authentication/","section":"Tags","summary":"","title":"Authentication"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/communication/","section":"Tags","summary":"","title":"Communication"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/conflict-management/","section":"Tags","summary":"","title":"Conflict-Management"},{"content":"Era un giovedì pomeriggio, una di quelle riunioni che sulla carta doveva durare un\u0026rsquo;ora. Eravamo in sette, collegati in call. L\u0026rsquo;ordine del giorno era semplice: decidere la strategia di migrazione di un database Oracle da on-premise a cloud.\nSemplice, appunto. Sulla carta.\nDopo venti minuti, la riunione si era trasformata in un duello.\n🔥 La scintilla #Da una parte c\u0026rsquo;era il responsabile infrastruttura. Uomo di esperienza, vent\u0026rsquo;anni di datacenter alle spalle. La sua posizione era granitica: migrazione lift-and-shift, zero modifiche all\u0026rsquo;architettura, si porta tutto così com\u0026rsquo;è.\nDall\u0026rsquo;altra, il lead developer. Giovane, brillante, con le idee chiare. Voleva riscrivere lo strato applicativo, adottare servizi cloud-native, containerizzare tutto. Rifacciamo da zero, tanto il codice è vecchio.\nDue posizioni legittime. Due prospettive reali. Due persone intelligenti.\nMa la conversazione aveva preso una piega familiare — e pericolosa.\n\u0026ldquo;No, non ha senso portare tutto su cloud senza ripensare l\u0026rsquo;architettura.\u0026rdquo;\n\u0026ldquo;No, riscrivere tutto è un rischio enorme e non abbiamo il budget.\u0026rdquo;\nNo. No. No.\nOgni frase iniziava con \u0026ldquo;no\u0026rdquo;. Ogni risposta era una negazione di quella precedente. Le braccia incrociate, il tono che saliva, le frasi che si accorciavano. Conosco quello schema. L\u0026rsquo;ho visto centinaia di volte. E so come finisce: non finisce. La riunione si chiude senza decisione, si rimanda alla prossima settimana, e nel frattempo nessuno fa niente perché \u0026ldquo;non abbiamo ancora deciso\u0026rdquo;.\nIl progetto si ferma. Non per motivi tecnici. Per orgoglio.\n🎭 Tre parole che cambiano tutto #A quel punto ho fatto una cosa molto semplice. Ho aspettato una pausa — perché nelle discussioni accese c\u0026rsquo;è sempre un momento in cui tutti riprendono fiato — e ho detto:\n\u0026ldquo;Marco, hai ragione: portare tutto su cloud senza cambiare nulla è il modo più veloce per andare in produzione. E potremmo anche identificare due o tre componenti che, migrando, ha senso ripensare in chiave cloud-native. Luca, tu quali sceglieresti?\u0026rdquo;\nNessuno ha detto \u0026ldquo;no\u0026rdquo;. Nessuno è stato contraddetto.\nMarco si è visto dare ragione — il suo approccio conservativo era il punto di partenza. Luca si è visto offrire un ruolo concreto — scegliere cosa modernizzare, con un mandato preciso.\nIn trenta secondi, due persone che stavano litigando si sono ritrovate a collaborare sulla stessa lavagna.\nLa riunione è finita in anticipo. Con una decisione. Una vera.\n🧠 Cos\u0026rsquo;è la tecnica del \u0026ldquo;Sì-E\u0026rdquo; #Quello che ho fatto ha un nome. Si chiama \u0026ldquo;Yes-And\u0026rdquo; — in italiano, \u0026ldquo;Sì-E\u0026rdquo;. Viene dal teatro di improvvisazione, dove c\u0026rsquo;è una regola fondamentale: non negare mai la proposta del tuo partner di scena.\nSe qualcuno dice \u0026ldquo;Siamo su una barca in mezzo all\u0026rsquo;oceano\u0026rdquo;, tu non rispondi \u0026ldquo;No, siamo in un ufficio\u0026rdquo;. Rispondi \u0026ldquo;Sì, e sembra che stia arrivando una tempesta\u0026rdquo;. Costruisci. Aggiungi. Vai avanti.\nNel project management funziona allo stesso modo.\nQuando qualcuno propone qualcosa e tu rispondi \u0026ldquo;No, però\u0026hellip;\u0026rdquo;, succede questo a livello psicologico:\nl\u0026rsquo;interlocutore si mette sulla difensiva smette di ascoltare quello che viene dopo il \u0026ldquo;però\u0026rdquo; si concentra su come ribattere, non su come risolvere la conversazione diventa un ping-pong di negazioni Quando rispondi \u0026ldquo;Sì, e\u0026hellip;\u0026rdquo;, succede il contrario:\nl\u0026rsquo;interlocutore si sente riconosciuto abbassa le difese diventa disponibile ad ascoltare la tua aggiunta la conversazione diventa costruttiva Non è manipolazione. Non è diplomazia vuota. È una tecnica precisa per far progredire le decisioni senza bruciare i rapporti.\n🛠️ Come funziona nella pratica quotidiana #In trent\u0026rsquo;anni di progetti, ho applicato il \u0026ldquo;Sì-E\u0026rdquo; in decine di situazioni. Funziona ovunque ci sia una decisione da prendere e più persone con opinioni diverse.\nNelle riunioni di progetto #Invece di: \u0026ldquo;No, la timeline di tre mesi è irrealistica.\u0026rdquo;\nProva con: \u0026ldquo;Sì, tre mesi è l\u0026rsquo;obiettivo. E per arrivarci dovremmo tagliare lo scope del primo rilascio a queste tre funzionalità — le altre le mettiamo nella fase due.\u0026rdquo;\nNoti la differenza? Nella prima versione hai un muro. Nella seconda hai un piano.\nNelle code review #Invece di: \u0026ldquo;No, questo approccio è sbagliato, l\u0026rsquo;hai scritto in modo troppo complicato.\u0026rdquo;\nProva con: \u0026ldquo;Sì, funziona. E potremmo semplificarlo estraendo questa logica in un metodo separato — diventa più testabile.\u0026rdquo;\nLo sviluppatore non si sente attaccato. Si sente aiutato. E la prossima volta viene da te a chiedere un parere prima di scrivere il codice, non dopo.\nNelle negoziazioni con gli stakeholder #Invece di: \u0026ldquo;No, non possiamo aggiungere quella feature adesso, siamo già in ritardo.\u0026rdquo;\nProva con: \u0026ldquo;Sì, quella feature ha senso. E per inserirla senza compromettere la data di rilascio, dovremmo sostituirla con questa altra che è meno prioritaria. Quale delle due preferite?\u0026rdquo;\nLo stakeholder non sente un \u0026ldquo;no\u0026rdquo;. Sente un \u0026ldquo;sì, e ora decidiamo insieme come farlo\u0026rdquo;.\n⚠️ Quando il \u0026ldquo;Sì-E\u0026rdquo; non funziona #Sarebbe bello dire che funziona sempre. Non è così. Ci sono situazioni in cui il \u0026ldquo;Sì-E\u0026rdquo; è lo strumento sbagliato.\nProblemi di sicurezza. Se qualcuno propone di togliere l\u0026rsquo;autenticazione dal database di produzione perché \u0026ldquo;rallenta le query\u0026rdquo;, la risposta non è \u0026ldquo;Sì, e\u0026hellip;\u0026rdquo;. La risposta è \u0026ldquo;No. Punto.\u0026rdquo;\nViolazioni di processo. Se uno sviluppatore vuole fare il deploy in produzione il venerdì sera senza test, non c\u0026rsquo;è \u0026ldquo;Sì-E\u0026rdquo; che tenga. C\u0026rsquo;è un processo, e va rispettato.\nDeadline non negoziabili. Quando il go-live è lunedì e siamo a giovedì, non è il momento di costruire sopra le idee di tutti. È il momento di decidere, eseguire e chiudere.\nComportamenti tossici. Il \u0026ldquo;Sì-E\u0026rdquo; funziona con persone in buona fede che hanno opinioni diverse. Non funziona con chi vuole solo avere ragione, con chi boicotta, con chi non ascolta per principio. In quei casi serve un altro tipo di conversazione — privata, diretta e molto franca.\nLa tecnica non è una formula magica. È uno strumento. E come tutti gli strumenti, devi sapere quando usarlo e quando metterlo giù.\n📊 Il costo nascosto del \u0026ldquo;No, però\u0026hellip;\u0026rdquo; #Ho provato a fare un calcolo approssimativo su un progetto che ho gestito due anni fa. Un team di otto persone, riunioni tre volte a settimana.\nSituazione Durata media riunione Decisioni prese Prima (cultura del \u0026ldquo;No, però\u0026hellip;\u0026rdquo;) 1h 20min 0.5 per riunione Dopo (cultura del \u0026ldquo;Sì, e\u0026hellip;\u0026rdquo;) 45min 1.8 per riunione Il team prendeva decisioni tre volte più velocemente e le riunioni duravano quasi la metà.\nNon ho numeri scientifici. Sono dati empirici, raccolti su un progetto specifico. Ma il pattern è coerente con quello che ho visto in vent\u0026rsquo;anni: i team che discutono in modo costruttivo vanno più veloci di quelli che litigano. Non perché evitano il conflitto — perché lo attraversano meglio.\n🎯 Quello che ho imparato #Il \u0026ldquo;Sì-E\u0026rdquo; non è diplomazia. Non è evitare il confronto. Non è dire sì a tutto.\nÈ riconoscere che la maggior parte delle discussioni nei progetti IT non riguarda chi ha ragione. Riguarda come far progredire le cose. E le cose progrediscono quando le persone si sentono ascoltate, non quando vengono sconfitte.\nHo visto progetti bloccarsi per settimane perché due persone brillanti non riuscivano a smettere di dirsi \u0026ldquo;no\u0026rdquo; a vicenda. E ho visto gli stessi progetti sbloccarsi in quindici minuti quando qualcuno ha avuto il buon senso di dire \u0026ldquo;sì, e\u0026hellip;\u0026rdquo;.\nNon serve un corso di comunicazione. Non serve un coach. Serve provare, la prossima volta che qualcuno dice qualcosa con cui non sei d\u0026rsquo;accordo, a rispondere \u0026ldquo;Sì, e\u0026hellip;\u0026rdquo; invece di \u0026ldquo;No, però\u0026hellip;\u0026rdquo;.\nUn esercizio semplice. Che cambia il modo in cui le decisioni vengono prese.\nChe cambia il modo in cui le persone lavorano insieme.\nE che, a volte, salva una riunione che stava per esplodere.\n💬 A chi è capitato almeno una volta #Se hai mai partecipato a una riunione dove due persone si parlavano addosso e nessuno ascoltava nessuno. Se hai mai visto un progetto bloccarsi non per un problema tecnico, ma per un problema di comunicazione. Se hai mai pensato \u0026ldquo;ma perché non riusciamo semplicemente a decidere?\u0026rdquo;\nProva il \u0026ldquo;Sì-E\u0026rdquo;. La prossima riunione. Una volta sola.\nNon costa niente. Non richiede approvazione. Non serve un budget.\nServe solo la capacità di trattenerti un secondo prima di dire \u0026ldquo;no\u0026rdquo; — e sostituirlo con \u0026ldquo;sì, e\u0026hellip;\u0026rdquo;.\nIl risultato potrebbe sorprenderti.\nGlossario #Yes-And — Tecnica di comunicazione nata nel teatro di improvvisazione che sostituisce il \u0026ldquo;No, però\u0026hellip;\u0026rdquo; con \u0026ldquo;Sì, e\u0026hellip;\u0026rdquo;, trasformando le discussioni in costruzione collaborativa.\nStakeholder — Persona o gruppo con un interesse diretto nel risultato di un progetto: committente, utente finale, sponsor, team tecnico o qualsiasi parte influenzata dalle decisioni progettuali.\nScope — Perimetro di un progetto che definisce cosa è incluso e cosa è escluso: funzionalità, deliverable, vincoli e confini concordati con gli stakeholder.\nLift-and-Shift — Strategia di migrazione che sposta un sistema da un ambiente a un altro senza modificarne l\u0026rsquo;architettura, il codice o la configurazione.\nTimeboxing — Tecnica di gestione del tempo che assegna un intervallo fisso e non negoziabile a un\u0026rsquo;attività, forzando la conclusione entro il limite stabilito.\n","date":"13 gennaio 2026","permalink":"https://ivanluminaria.com/it/posts/project-management/tecnica-si-e-yes-and/","section":"Database Strategy","summary":"\u003cp\u003eEra un giovedì pomeriggio, una di quelle riunioni che sulla carta doveva durare un\u0026rsquo;ora. Eravamo in sette, collegati in call. L\u0026rsquo;ordine del giorno era semplice: decidere la strategia di migrazione di un database Oracle da on-premise a cloud.\u003c/p\u003e\n\u003cp\u003eSemplice, appunto. Sulla carta.\u003c/p\u003e\n\u003cp\u003eDopo venti minuti, la riunione si era trasformata in un duello.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"-la-scintilla\" class=\"relative group\"\u003e🔥 La scintilla \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-la-scintilla\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eDa una parte c\u0026rsquo;era il responsabile infrastruttura. Uomo di esperienza, vent\u0026rsquo;anni di datacenter alle spalle. La sua posizione era granitica: \u003cstrong\u003emigrazione lift-and-shift, zero modifiche all\u0026rsquo;architettura, si porta tutto così com\u0026rsquo;è\u003c/strong\u003e.\u003c/p\u003e","title":"La tecnica del Sì-E: come ho evitato una discussione che stava per esplodere"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/team-leadership/","section":"Tags","summary":"","title":"Team-Leadership"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/users/","section":"Tags","summary":"","title":"Users"},{"content":"Qualche settimana fa un cliente mi chiama. Tono pragmatico, richiesta apparentemente banale:\n\u0026ldquo;Devo creare un utente su MySQL per un\u0026rsquo;applicazione che deve accedere a un database. Puoi occupartene?\u0026rdquo;\nCerto. CREATE USER, `GRANT` , avanti il prossimo.\nSolo che poi aggiunge: \u0026ldquo;L\u0026rsquo;applicazione gira su due server diversi. E a volte ci collegheremo anche da locale per manutenzione.\u0026rdquo;\nEcco. Qui la cosa smette di essere banale. Perché in MySQL, creare \u0026ldquo;un utente\u0026rdquo; non significa quello che pensi.\nIl modello di autenticazione di MySQL: utente + host #La prima cosa da capire — e che molti DBA con background Oracle o PostgreSQL scoprono a proprie spese — è che in MySQL l\u0026rsquo;identità di un utente non è solo il nome.\nÈ la coppia 'utente'@'host'.\nQuesto significa che:\n\u0026#39;mario\u0026#39;@\u0026#39;localhost\u0026#39; \u0026#39;mario\u0026#39;@\u0026#39;192.168.1.10\u0026#39; \u0026#39;mario\u0026#39;@\u0026#39;%\u0026#39; non sono lo stesso utente. Sono tre utenti diversi. Con password diverse, privilegi diversi, comportamenti diversi.\nQuando MySQL riceve una connessione, guarda due cose:\nIl nome utente fornito L\u0026rsquo;indirizzo IP (o hostname) da cui arriva la connessione Poi cerca nella tabella mysql.user la riga che corrisponde alla coppia più specifica. Non la prima trovata. La più specifica.\nPerché questo modello? #La scelta progettuale non è casuale. MySQL è nato nel 1995 per il web. Ambienti dove lo stesso database serve applicazioni che girano su macchine diverse, reti diverse, con esigenze di accesso diverse.\nIl modello utente@host permette di:\ndare accesso completo da localhost (per il DBA) dare accesso limitato da un application server specifico bloccare tutto il resto Senza firewall. Senza VPN. Direttamente nel motore di autenticazione.\nÈ un modello potente. Ma se non lo capisci, ti morde.\nIl caso del cliente: come l\u0026rsquo;ho risolto #Torniamo alla richiesta. L\u0026rsquo;applicazione gira su due server (192.168.1.20 e 192.168.1.21) e serve anche un accesso locale per manutenzione.\nLa tentazione è creare un unico utente con '%' (wildcard = qualsiasi host):\nCREATE USER \u0026#39;app_vendite\u0026#39;@\u0026#39;%\u0026#39; IDENTIFIED BY \u0026#39;PasswordSicura#2026\u0026#39;; GRANT SELECT, INSERT, UPDATE ON vendite_db.* TO \u0026#39;app_vendite\u0026#39;@\u0026#39;%\u0026#39;; Funziona? Sì. È corretto? No.\nIl problema del '%' è che accetta connessioni da qualsiasi IP. Se domani qualcuno trova la password, può connettersi da qualunque punto della rete. O del mondo, se il database è esposto.\nLa soluzione corretta è creare utenti specifici per ogni sorgente:\n-- Accesso dall\u0026#39;application server primario CREATE USER \u0026#39;app_vendite\u0026#39;@\u0026#39;192.168.1.20\u0026#39; IDENTIFIED BY \u0026#39;PasswordSicura#2026\u0026#39;; GRANT SELECT, INSERT, UPDATE ON vendite_db.* TO \u0026#39;app_vendite\u0026#39;@\u0026#39;192.168.1.20\u0026#39;; -- Accesso dall\u0026#39;application server secondario CREATE USER \u0026#39;app_vendite\u0026#39;@\u0026#39;192.168.1.21\u0026#39; IDENTIFIED BY \u0026#39;PasswordSicura#2026\u0026#39;; GRANT SELECT, INSERT, UPDATE ON vendite_db.* TO \u0026#39;app_vendite\u0026#39;@\u0026#39;192.168.1.21\u0026#39;; -- Accesso locale per manutenzione (privilegi diversi) CREATE USER \u0026#39;app_vendite\u0026#39;@\u0026#39;localhost\u0026#39; IDENTIFIED BY \u0026#39;PasswordManut#2026\u0026#39;; GRANT SELECT ON vendite_db.* TO \u0026#39;app_vendite\u0026#39;@\u0026#39;localhost\u0026#39;; Tre utenti. Stesso nome. Privilegi calibrati.\nL\u0026rsquo;utente locale ha solo SELECT perché serve per verifiche, non per scrivere dati. Password diversa perché il contesto di utilizzo è diverso.\nPrincipio del privilegio minimo . Applicato nel punto giusto.\nLa trappola del matching: chi vince? #Questo è il punto dove la maggior parte degli errori nasce.\nSe esistono sia 'mario'@'%' che 'mario'@'localhost', e Mario si connette da localhost, quale utente viene usato?\nRisposta: 'mario'@'localhost'.\nMySQL ordina le righe nella tabella mysql.user dalla più specifica alla meno specifica:\nHost letterale esatto (192.168.1.20) Pattern con wildcard (192.168.1.%) Wildcard totale (%) E usa la prima corrispondenza nell\u0026rsquo;ordine di specificità.\nIl problema classico è questo: crei 'mario'@'%' con tutti i privilegi. Poi qualcuno crea 'mario'@'localhost' senza privilegi (o con una password diversa). Da quel momento, Mario da locale non riesce più a entrare e nessuno capisce perché.\nHo visto questo scenario almeno una dozzina di volte in produzione. La soluzione è sempre la stessa: verifica cosa esiste prima di creare.\nSELECT user, host, authentication_string FROM mysql.user WHERE user = \u0026#39;mario\u0026#39;; Se non lo fai prima, lo farai dopo. Con più urgenza e meno calma.\nMySQL vs MariaDB: le differenze che contano #Il modello utente@host è identico tra MySQL e MariaDB. Ma ci sono differenze nell\u0026rsquo;implementazione che vale la pena conoscere.\nAutenticazione di default:\nVersione Plugin di default MySQL 5.7 mysql_native_password MySQL 8.0+ caching_sha2_password MariaDB 10.x mysql_native_password Se migri da MariaDB a MySQL 8 (o viceversa), i client potrebbero non connettersi perché il plugin di autenticazione è diverso. Non è un bug. È un cambio di default.\nCreazione utenti:\nIn MySQL 8, GRANT non crea più utenti implicitamente. Devi fare CREATE USER prima e GRANT dopo. Sempre.\n-- MySQL 8: corretto CREATE USER \u0026#39;app\u0026#39;@\u0026#39;10.0.0.5\u0026#39; IDENTIFIED BY \u0026#39;pwd123\u0026#39;; GRANT SELECT ON mydb.* TO \u0026#39;app\u0026#39;@\u0026#39;10.0.0.5\u0026#39;; -- MySQL 5.7 / MariaDB: funziona ancora (ma è deprecato) GRANT SELECT ON mydb.* TO \u0026#39;app\u0026#39;@\u0026#39;10.0.0.5\u0026#39; IDENTIFIED BY \u0026#39;pwd123\u0026#39;; Se stai scrivendo script di provisioning, questo dettaglio può rompere una pipeline CI/CD intera.\nRuoli:\nMySQL 8.0 ha introdotto i ruoli. MariaDB li supporta dalla 10.0.5, ma con sintassi leggermente diversa.\n-- MySQL 8.0 CREATE ROLE \u0026#39;role_lettura\u0026#39;; GRANT SELECT ON vendite_db.* TO \u0026#39;role_lettura\u0026#39;; GRANT \u0026#39;role_lettura\u0026#39; TO \u0026#39;app_vendite\u0026#39;@\u0026#39;192.168.1.20\u0026#39;; SET DEFAULT ROLE \u0026#39;role_lettura\u0026#39; FOR \u0026#39;app_vendite\u0026#39;@\u0026#39;192.168.1.20\u0026#39;; -- MariaDB 10.x CREATE ROLE role_lettura; GRANT SELECT ON vendite_db.* TO role_lettura; GRANT role_lettura TO \u0026#39;app_vendite\u0026#39;@\u0026#39;192.168.1.20\u0026#39;; SET DEFAULT ROLE role_lettura FOR \u0026#39;app_vendite\u0026#39;@\u0026#39;192.168.1.20\u0026#39;; La differenza sembra cosmetica (apici o no), ma in script automatizzati può generare errori sintattici.\nL\u0026rsquo;utente anonimo: il fantasma che nessuno invita #MySQL viene installato con un utente anonimo : ''@'localhost'. Nessun nome, nessuna password.\nQuesto utente è un residuo storico delle installazioni di sviluppo. In produzione è un rischio di sicurezza puro.\nL\u0026rsquo;utente anonimo vince su 'mario'@'%' quando la connessione arriva da localhost, perché 'localhost' è più specifico di '%'.\nRisultato: Mario si connette da locale, MySQL lo autentica come utente anonimo, e i privilegi di Mario scompaiono.\nLa prima cosa da fare su qualsiasi installazione MySQL/MariaDB in produzione:\nSELECT user, host FROM mysql.user WHERE user = \u0026#39;\u0026#39;; -- Se trovato: DROP USER \u0026#39;\u0026#39;@\u0026#39;localhost\u0026#39;; DROP USER \u0026#39;\u0026#39;@\u0026#39;%\u0026#39;; -- se esiste FLUSH PRIVILEGES ; Non è paranoia. È igiene.\nChecklist operativa #Dopo l\u0026rsquo;esperienza con il cliente, ho formalizzato una checklist che uso ogni volta che devo creare utenti su MySQL o MariaDB:\nVerifica utenti esistenti con lo stesso nome su host diversi Elimina utenti anonimi se presenti Crea utenti con host specifici, mai con '%' in produzione se non strettamente necessario Assegna solo i privilegi necessari — SELECT se basta SELECT Usa CREATE USER + GRANT separati (obbligatorio su MySQL 8) Verifica il plugin di autenticazione se i client hanno problemi di connessione Documenta le coppie utente/host — tra sei mesi nessuno si ricorderà perché esistono tre \u0026ldquo;app_vendite\u0026rdquo; Conclusione #In MySQL e MariaDB un utente non è un nome. È un nome legato a un punto di origine.\nQuesto modello è potente perché permette di segmentare gli accessi senza infrastruttura aggiuntiva. Ma è anche una fonte di errori subdoli se non lo si comprende a fondo.\nLa prossima volta che qualcuno ti chiede \u0026ldquo;crea un utente su MySQL\u0026rdquo;, prima di scrivere il primo CREATE USER, chiediti: da dove si connetterà?\nLa risposta a quella domanda cambia tutto.\nGlossario #GRANT — Comando SQL per assegnare privilegi a un utente o ruolo. In MySQL 8 non crea più utenti implicitamente: serve prima CREATE USER, poi GRANT.\nLeast Privilege — Principio di sicurezza che prevede l\u0026rsquo;assegnazione solo dei permessi strettamente necessari. In MySQL si applica calibrando privilegi per coppia utente/host.\nAuthentication Plugin — Modulo che gestisce la verifica delle credenziali. Il default cambia tra MySQL 5.7 (mysql_native_password), MySQL 8 (caching_sha2_password) e MariaDB.\nAnonymous User — Utente MySQL senza nome (''@'localhost') creato automaticamente durante l\u0026rsquo;installazione. Può interferire con il matching degli utenti legittimi e va rimosso in produzione.\nFLUSH PRIVILEGES — Comando che ricarica le tabelle dei grant in memoria, rendendo effettive le modifiche manuali ai privilegi. Necessario dopo operazioni dirette sulla tabella mysql.user.\n","date":"13 gennaio 2026","permalink":"https://ivanluminaria.com/it/posts/mysql/mysql-users-and-hosts/","section":"Database Strategy","summary":"\u003cp\u003eQualche settimana fa un cliente mi chiama. Tono pragmatico, richiesta apparentemente banale:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u0026ldquo;Devo creare un utente su MySQL per un\u0026rsquo;applicazione che deve accedere a un database. Puoi occupartene?\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eCerto. \u003ccode\u003eCREATE USER\u003c/code\u003e, \u003cspan class=\"glossary-tip\" tabindex=\"0\" data-glossary-desc=\"Comando SQL per assegnare privilegi specifici a un utente o ruolo su database, tabelle o colonne. In MySQL 8 non crea più utenti implicitamente.\" data-glossary-url=\"/it/glossary/grant/\" data-glossary-more=\"Leggi di più →\"\u003e`GRANT`\u003c/span\u003e\n, avanti il prossimo.\u003c/p\u003e\n\u003cp\u003eSolo che poi aggiunge: \u0026ldquo;L\u0026rsquo;applicazione gira su due server diversi. E a volte ci collegheremo anche da locale per manutenzione.\u0026rdquo;\u003c/p\u003e","title":"Utenti MySQL: perché 'mario' e 'mario'@'localhost' non sono la stessa persona"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/indexes/","section":"Tags","summary":"","title":"Indexes"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/pg_trgm/","section":"Tags","summary":"","title":"Pg_trgm"},{"content":"Qualche settimana fa un cliente mi contatta con un problema molto comune:\n\u0026ldquo;La ricerca nella console amministrativa è lenta. A volte impiega diversi secondi. Abbiamo già ridotto le JOIN, ma il problema non è sparito.\u0026rdquo;\nAmbiente: PostgreSQL su cloud managed.\nTabella principale: payment_report (~6 milioni di righe, 3 GB).\nColonna ricercata: reference_code.\nQuery incriminata:\nSELECT * FROM reporting.payment_report r JOIN reporting.payment_cart c ON c.id = r.cart_id WHERE c.service_id = 1001 AND r.reference_code LIKE \u0026#39;%ABC123%\u0026#39; ORDER BY c.created_at DESC LIMIT 100; 🧠 Prima osservazione: il problema non erano le JOIN #Ho confrontato:\nversione AS-IS (3 JOIN sulla stessa tabella) versione TO-BE (1 sola JOIN) Risultato?\nIl piano di esecuzione mostrava in entrambi i casi:\nParallel Seq Scan on payment_report Rows Removed by Filter: ~2.000.000 Buffers: shared read = centinaia di migliaia Execution Time: 14–18 secondi La riduzione delle JOIN aveva un impatto marginale.\nIl vero problema era un altro.\n📌 Il colpevole: LIKE '%valore%' senza indice adatto #La ricerca con wildcard iniziale (%valore%) rende inutilizzabile un normale indice B-Tree .\nPostgreSQL è costretto a fare una scansione sequenziale dell\u0026rsquo;intera tabella.\nNel caso specifico:\n~3 GB di dati centinaia di migliaia di pagine da 8KB lette I/O dominante secondi di latenza Non è un problema di SQL \u0026ldquo;brutto\u0026rdquo;. È un problema di access path.\n🔬 Prima di creare un indice: analisi del rischio #Il cliente giustamente chiede:\n\u0026ldquo;Se creiamo un indice trigram (GIN), rischiamo di rallentare le transazioni di pagamento?\u0026rdquo;\nQui entra in gioco un concetto spesso ignorato: il **churn** .\nCos\u0026rsquo;è il churn? #È quanto una tabella cambia dopo che le righe sono state inserite.\nAlta frequenza di: - UPDATE - DELETE\n→ alto churn\n→ maggiore costo di manutenzione indice\n→ possibile degrado scritture\nNel nostro caso:\nTabella payment_report: - ~12k insert/giorno - 0 update - 0 delete - 0 dead tuples\nProfilo: append-only\nQuesto è il miglior scenario possibile per introdurre un GIN.\n📊 Verifica fondamentale: sincrono o batch? #La tabella non aveva timestamp di inserimento.\nSoluzione: analisi indiretta.\nHo correlato le righe di payment_report al timestamp del carrello (payment_cart.created_at) e ho analizzato la distribuzione oraria.\nRisultato:\nandamento continuo 24/7 picchi diurni calo notturno perfetta correlazione con il traffico carrelli Conclusione: popolamento near real-time, non batch notturno.\n🛠️ La soluzione #CREATE EXTENSION IF NOT EXISTS pg_trgm ; CREATE INDEX CONCURRENTLY idx_payment_report_reference_trgm ON reporting.payment_report USING gin (reference_code gin_trgm_ops); Precauzioni:\nCreazione in finestra off-peak Modalità CONCURRENTLY Monitoraggio I/O durante la build 📈 Risultato: il piano di esecuzione prima e dopo #Ecco il piano di esecuzione completo della query — prima e dopo la creazione dell\u0026rsquo;indice trigram.\nPrima (senza indice trigram):\nNested Loop Inner Join → Nested Loop Inner Join → Nested Loop Inner Join → Seq Scan on payment_report as r Filter: ((reference_code)::text ~~ \u0026#39;%ABC123%\u0026#39;::text) → Index Scan using payment_cart_pkey on payment_cart as c Filter: (service_id = 1001) Index Cond: (id = r.cart_id) → Index Only Scan using payment_cart_pkey on payment_cart as c2 Index Cond: (id = c.id) → Index Only Scan using payment_cart_pkey on payment_cart as c3 Index Cond: (id = c.id) Dopo (con indice trigram):\nNested Loop Inner Join → Nested Loop Inner Join → Nested Loop Inner Join → Bitmap Heap Scan on payment_report as r Recheck Cond: ((reference_code)::text ~~ \u0026#39;%ABC123%\u0026#39;::text) → Bitmap Index Scan using idx_payment_report_reference_trgm Index Cond: ((reference_code)::text ~~ \u0026#39;%ABC123%\u0026#39;::text) → Index Scan using payment_cart_pkey on payment_cart as c Filter: (service_id = 1001) Index Cond: (id = r.cart_id) → Index Only Scan using payment_cart_pkey on payment_cart as c2 Index Cond: (id = c.id) → Index Only Scan using payment_cart_pkey on payment_cart as c3 Index Cond: (id = c.id) Il punto chiave è allo step 4–5: il Seq Scan — che leggeva l\u0026rsquo;intera tabella riga per riga — è stato sostituito da un Bitmap Heap Scan guidato dall\u0026rsquo;indice trigram idx_payment_report_reference_trgm. PostgreSQL ora filtra direttamente via indice e fa il recheck solo sulle righe candidate.\nStessa query, stesso dato, ma un access path completamente diverso. Da secondi a millisecondi.\n🎯 Lezione chiave #Quando una query è lenta:\nNon fermarti al numero di JOIN. Guarda il piano di esecuzione. Identifica se il problema è CPU o I/O. Valuta il churn prima di introdurre un indice GIN. Misura sempre prima di decidere. Spesso il problema non è \u0026ldquo;ottimizzare la query\u0026rdquo;. È dare al planner l\u0026rsquo;indice giusto.\n💬 Perché condivido questo caso? #Perché è uno scenario estremamente comune:\nTabelle grandi Ricerca \u0026ldquo;contiene\u0026rdquo; Paura di introdurre indici GIN Timore di degradare le scritture Con dati alla mano, la decisione diventa tecnica, non emotiva.\nL\u0026rsquo;ottimizzazione non è magia. È misurazione, lettura dei piani e comprensione del comportamento reale del sistema.\nGlossario #GIN Index — Generalized Inverted Index: tipo di indice PostgreSQL che crea un mapping inverso da ogni elemento ai record che lo contengono. Ideale per ricerche \u0026ldquo;contiene\u0026rdquo; su testo con pg_trgm.\nB-Tree — Struttura dati ad albero bilanciato, indice predefinito nei database relazionali. Efficiente per ricerche di uguaglianza e range, ma inutilizzabile per LIKE '%valore%'.\npg_trgm — Estensione PostgreSQL che scompone il testo in trigrammi (sequenze di 3 caratteri), abilitando l\u0026rsquo;uso di indici GIN per accelerare ricerche con wildcard.\nChurn — Misura di quanto una tabella cambia dopo l\u0026rsquo;inserimento. Basso churn (append-only) è il miglior scenario per introdurre un indice GIN senza degradare le scritture.\nExecution Plan — Sequenza di operazioni scelta dal database per risolvere una query. Leggere il piano è il primo passo per identificare se il problema è CPU, I/O o un access path sbagliato.\n","date":"6 gennaio 2026","permalink":"https://ivanluminaria.com/it/posts/postgresql/like-optimization-postgresql/","section":"Database Strategy","summary":"\u003cp\u003eQualche settimana fa un cliente mi contatta con un problema molto\ncomune:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u0026ldquo;La ricerca nella console amministrativa è lenta. A volte impiega\ndiversi secondi. Abbiamo già ridotto le JOIN, ma il problema non è\nsparito.\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eAmbiente: PostgreSQL su cloud managed.\u003cbr\u003e\nTabella principale: \u003ccode\u003epayment_report\u003c/code\u003e (~6 milioni di righe, 3 GB).\u003cbr\u003e\nColonna ricercata: \u003ccode\u003ereference_code\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eQuery incriminata:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ereporting\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epayment_report\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003er\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eJOIN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ereporting\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epayment_cart\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eON\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ec\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003er\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecart_id\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eWHERE\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ec\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eservice_id\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1001\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"k\"\u003eAND\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003er\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereference_code\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eLIKE\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;%ABC123%\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eORDER\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eBY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ec\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecreated_at\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eDESC\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eLIMIT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e100\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"-prima-osservazione-il-problema-non-erano-le-join\" class=\"relative group\"\u003e🧠 Prima osservazione: il problema non erano le JOIN \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-prima-osservazione-il-problema-non-erano-le-join\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eHo confrontato:\u003c/p\u003e","title":"Quando un LIKE '%valore%' rallenta tutto: un caso reale di ottimizzazione PostgreSQL"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/query-tuning/","section":"Tags","summary":"","title":"Query-Tuning"},{"content":"La storia che sto per raccontare è vera. I nomi non li faccio — non per diplomazia, ma perché i nomi non servono. Quello che serve è capire il meccanismo. Perché questo meccanismo si ripete, identico, in decine di aziende italiane. E costa milioni.\n🏢 Il cliente: un gruppo assicurativo con un\u0026rsquo;ambizione legittima #Un\u0026rsquo;azienda solida del settore assicurativo. Operazioni in Italia, Francia, paesi del Nord Europa, Spagna. Migliaia di dipendenti, milioni di polizze gestite, un business che cresce.\nAd un certo punto, la direzione prende una decisione ragionevole: ci serve un software gestionale su misura. Un sistema che rispecchi i nostri processi, le nostre regole di business, le specificità normative di ogni paese in cui operiamo.\nDecisione legittima. Sensata. Strategica, perfino.\nIl problema non è la decisione.\nIl problema è a chi la affidano.\n💰 Primo atto: la grande multinazionale (2013-2018) #Viene ingaggiata — in pieno outsourcing — una delle Big della consulenza IT mondiale. Nome che tutti conoscono. Migliaia di consulenti, sedi in ogni continente, presentazioni in PowerPoint che farebbero piangere di commozione.\nIl progetto parte. Si definiscono i requisiti. Si stima il budget. Si firmano i contratti.\nPassano i mesi. Poi gli anni.\nI deliverable arrivano — sulla carta. Ma il software non funziona come dovrebbe. Le specifiche cambiano. I costi lievitano. I consulenti ruotano: quello che aveva capito il dominio se ne va, arriva un altro che ricomincia da zero. Il classico schema della consulenza a corpo che diventa, nei fatti, una consulenza a tempo indeterminato.\nDal 2013 al 2018: oltre 2,5 milioni di euro spesi.\nRisultato: un software incompleto, instabile, che nessuno internamente sapeva manutenere.\nPerché il codice l\u0026rsquo;avevano scritto loro. Con le loro convenzioni. Con la loro architettura. E quando se ne sono andati, si sono portati via anche la conoscenza.\n🔄 Secondo atto: cambiamo fornitore (2018-2022) #Il management, scottato ma non rassegnato, decide di cambiare. \u0026ldquo;Il problema era il fornitore\u0026rdquo;, pensano. \u0026ldquo;Prendiamone uno migliore.\u0026rdquo;\nEntra in scena un\u0026rsquo;altra multinazionale. Altrettanto famosa. Altrettanto grande. Altrettanto costosa.\nNuovo kickoff. Nuova analisi dei requisiti — perché ovviamente non possono ripartire dal lavoro del fornitore precedente. Nuove slide. Nuove promesse.\nE la storia si ripete.\nStessi problemi, attori diversi. Turnover dei consulenti. Perdita di know-how. Tempi che si allungano. Budget che esplodono. Riunioni infinite in cui si discute di milestone che non arrivano mai.\nDal 2018 al 2022: altri 1,5 milioni di euro.\nRisultato: un altro software che non soddisfa le esigenze aziendali.\nTotale investito in quasi dieci anni: oltre 4 milioni di euro.\nSoftware funzionante: zero.\n📊 Facciamo i conti del disastro # Periodo Fornitore Investimento Risultato 2013 – 2018 Multinazionale A ~2.500.000 € Software incompleto, abbandonato 2018 – 2022 Multinazionale B ~1.500.000 € Software inadeguato, abbandonato Totale ~4.000.000+ € Nessun software in produzione Quattro milioni di euro. Quasi dieci anni di progetto. Due dei nomi più prestigiosi della consulenza IT globale.\nE alla fine, l\u0026rsquo;azienda si ritrova esattamente al punto di partenza.\nNon è sfortuna. È un pattern.\nE chi lavora in questo settore da trent\u0026rsquo;anni, come me, lo riconosce a prima vista.\n🧠 Perché succede: l\u0026rsquo;anatomia del fallimento #Questo tipo di fallimento non è un incidente. È il risultato prevedibile di un modello di business che ha un difetto strutturale.\n1. L\u0026rsquo;incentivo è sbagliato.\nUna grande società di consulenza guadagna vendendo giornate-uomo. Più il progetto dura, più fattura. Non c\u0026rsquo;è alcun incentivo reale a chiudere il progetto in fretta e bene. C\u0026rsquo;è un incentivo a tenerlo in vita il più a lungo possibile.\n2. Il turnover è endemico.\nLe multinazionali della consulenza hanno tassi di turnover del 15-25% annuo. In un progetto che dura cinque anni, il team si rinnova completamente almeno due volte. Ogni volta si ricomincia: nuova curva di apprendimento, nuova interpretazione dei requisiti, nuovi errori.\n3. Il know-how esce dalla porta (vendor lock-in ).\nQuando il fornitore finisce (o viene cacciato), la conoscenza del sistema se ne va con lui. Il cliente resta con un software che non capisce, non sa manutenere e non può evolvere.\n4. Le specifiche diventano un\u0026rsquo;arma (scope creep ).\nIn un progetto custom di questa portata, le specifiche sono sempre incomplete — perché il business è complesso e in evoluzione. Questo diventa l\u0026rsquo;alibi perfetto: \u0026ldquo;il software non funziona perché le specifiche sono cambiate\u0026rdquo;. Ed è sempre colpa di qualcun altro.\n✅ La svolta: comprare, non costruire #Alla fine, dopo quasi un decennio e oltre 4 milioni bruciati, l\u0026rsquo;azienda prende la decisione che avrebbe dovuto prendere all\u0026rsquo;inizio:\nAcquistare un software di mercato già funzionante e adattarlo internamente alle proprie esigenze.\nUn prodotto assicurativo commerciale, collaudato, con una base di codice stabile e una community di supporto. E un team interno — persone che conoscono il business, che restano in azienda, che accumulano conoscenza invece di disperderla — incaricato di personalizzarlo ed evolverlo.\nCosto? Una frazione di quello speso nei dieci anni precedenti.\nRisultato? Un sistema che funziona. Che evolve. Che l\u0026rsquo;azienda possiede davvero.\nLa lezione è brutale nella sua semplicità:\nNon tutto va costruito da zero. E soprattutto, non tutto va delegato a chi non ha interesse a finire.\n🏗️ Il paragone che fa male: il nostro Data Warehouse #E qui entra la parte della storia che conosco da dentro. Perché per la stessa azienda, nello stesso periodo, io e un collega abbiamo costruito qualcosa che funziona. Ogni singolo giorno.\nUn **Data Warehouse** completo. Progettato, sviluppato, messo in produzione e mantenuto in due persone.\nNon una demo. Non un prototipo. Un sistema di produzione che:\nCarica dati ogni giorno — l\u0026rsquo;intero ciclo ETL gira in un\u0026rsquo;ora e mezza Integra 4 sistemi sorgenti diversi — ognuno con il suo formato, il suo protocollo, le sue particolarità Raccoglie dati da 4 aree geografiche: Italia, Francia, paesi del Nord Europa, Spagna Comprende circa 60.000 righe di codice scritte a quattro mani L\u0026rsquo;architettura è stata disegnata da me — dal modello dati alla strategia di caricamento, dalla gestione degli errori alla storicizzazione Software gestionale custom Data Warehouse Team Due multinazionali (decine di consulenti) 2 persone Durata progetto ~10 anni (e contando) 3 anni Budget 4.000.000+ € Una frazione Righe di codice sconosciute (e abbandonate) ~60.000 (documentate, mantenute) Risultato Nessun software in produzione Sistema in produzione quotidiana Tempo di elaborazione — 1h 30min / giorno Copertura geografica — 4 paesi, 4 sistemi sorgente Know-how Perso ad ogni cambio fornitore Interno, stabile, documentato Due persone. Tre anni. Un sistema che ogni mattina si sveglia, raccoglie dati da quattro angoli d\u0026rsquo;Europa, li trasforma, li carica e li rende disponibili per le decisioni aziendali. In un\u0026rsquo;ora e mezza.\nSessantamila righe di codice. Ognuna pensata, testata, mantenuta da chi l\u0026rsquo;ha scritta.\nNessun PowerPoint. Nessun kickoff. Nessun consulente che se ne va portandosi via la conoscenza.\nSolo competenza, architettura solida e lavoro fatto bene.\n🎯 La lezione #Quando parlo con aziende che stanno per intraprendere un grande progetto IT, gli dico sempre la stessa cosa:\nNon pagate un brand. Pagate le persone.\nUn team piccolo di professionisti che conoscono il dominio, che restano sul progetto, che sono responsabili del risultato — vale più di cento consulenti a rotazione che fatturano giornate.\nIl software non si costruisce con le slide. Si costruisce con le mani nel codice, con l\u0026rsquo;architettura nella testa e con la responsabilità addosso.\nQuattro milioni di euro in fumo insegnano una cosa sola:\nIl costo più alto non è quello del fornitore che sbagli.\nÈ quello del tempo che perdi prima di capire che la soluzione era più semplice di quello che ti avevano venduto.\n💬 A chi sta per firmare quel contratto #Se la tua azienda sta per affidare un progetto critico a una grande società di consulenza, fermati un momento.\nChiediti:\nChi scriverà il codice? Resterà in azienda tra due anni? Se il fornitore se ne va domani, sapremmo manutenere il sistema? Esiste un prodotto di mercato che copre l'80% delle nostre esigenze? Possiamo costruire un team interno piccolo, competente e stabile? Le risposte a queste domande valgono più di qualsiasi proposta commerciale.\nPerché la differenza tra un progetto che funziona e uno che brucia milioni non sta nella tecnologia.\nSta nelle persone. Nella continuità. Nella responsabilità.\nE nella capacità di dire \u0026ldquo;no\u0026rdquo; a chi ti vende la complessità quando la soluzione è semplice.\nGlossario #Data Warehouse — Sistema centralizzato di raccolta e storicizzazione dati da fonti diverse, progettato per l\u0026rsquo;analisi e il supporto alle decisioni aziendali. Nel caso descritto, costruito in due persone con 60.000 righe di codice.\nETL — Extract, Transform, Load: processo di estrazione dati dai sistemi sorgente, trasformazione e caricamento nel data warehouse. Il ciclo ETL del DWH descritto gira in un\u0026rsquo;ora e mezza.\nVendor Lock-in — Dipendenza strutturale da un fornitore esterno che rende difficile cambiare provider. Si instaura quando il know-how e il codice restano nelle mani del fornitore.\nScope Creep — Espansione incontrollata dei requisiti di progetto oltre il perimetro iniziale. Le specifiche incomplete diventano l\u0026rsquo;alibi per ritardi e costi aggiuntivi.\nOutsourcing — Esternalizzazione di attività IT a fornitori esterni. Rischioso per progetti strategici a lungo termine, dove il turnover dei consulenti e la perdita di know-how possono bruciare milioni.\n","date":"30 dicembre 2025","permalink":"https://ivanluminaria.com/it/posts/project-management/4-milioni-nessun-software/","section":"Database Strategy","summary":"\u003cp\u003eLa storia che sto per raccontare è vera. I nomi non li faccio — non per diplomazia, ma perché i nomi non servono. Quello che serve è capire il meccanismo. Perché questo meccanismo si ripete, identico, in decine di aziende italiane. E costa milioni.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"-il-cliente-un-gruppo-assicurativo-con-unambizione-legittima\" class=\"relative group\"\u003e🏢 Il cliente: un gruppo assicurativo con un\u0026rsquo;ambizione legittima \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#-il-cliente-un-gruppo-assicurativo-con-unambizione-legittima\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn\u0026rsquo;azienda solida del settore assicurativo. Operazioni in Italia, Francia, paesi del Nord Europa, Spagna. Migliaia di dipendenti, milioni di polizze gestite, un business che cresce.\u003c/p\u003e","title":"4 milioni di euro, due multinazionali, zero software: storia vera di un fallimento annunciato"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/insurance/","section":"Tags","summary":"","title":"Insurance"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/outsourcing/","section":"Tags","summary":"","title":"Outsourcing"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/execution-plan/","section":"Tags","summary":"","title":"Execution-Plan"},{"content":"Due miliardi di righe. Non è un numero che si raggiunge in un giorno. Ci vogliono anni di transazioni, di movimenti, di registrazioni quotidiane che si accumulano. E per tutto quel tempo il database funziona, le query rispondono, i report escono. Poi un giorno qualcuno apre un ticket: \u0026ldquo;il report mensile ci mette quattro ore.\u0026rdquo;\nQuattro ore. Per un report che sei mesi prima ne impiegava venti minuti.\nNon è un bug. Non è un problema di rete o di storage lento. È la fisica dei dati: quando una tabella cresce oltre una certa soglia, gli approcci che funzionavano smettono di funzionare. E se non hai progettato la struttura per gestire quella crescita, il database fa l\u0026rsquo;unica cosa che può fare: leggere tutto.\nIl contesto: telecomunicazioni e volumi industriali #Il cliente era un operatore telecom. Niente di esotico — un classico ambiente Oracle 19c Enterprise Edition su Linux, storage SAN, una trentina di istanze tra produzione, staging e sviluppo. L\u0026rsquo;istanza critica era quella del billing: fatturazione, CDR (Call Detail Records), movimenti contabili.\nLa tabella al centro del problema si chiamava TXN_MOVIMENTI. Raccoglieva ogni singola transazione del sistema di billing dal 2016. La struttura era più o meno questa:\nCREATE TABLE txn_movimenti ( txn_id NUMBER(18) NOT NULL, data_movimento DATE NOT NULL, cod_cliente VARCHAR2(20) NOT NULL, tipo_movimento VARCHAR2(10) NOT NULL, importo NUMBER(15,4), canale VARCHAR2(30), stato VARCHAR2(5) DEFAULT \u0026#39;ATT\u0026#39;, data_insert TIMESTAMP DEFAULT SYSTIMESTAMP, CONSTRAINT pk_txn_movimenti PRIMARY KEY (txn_id) ); 2.1 miliardi di righe. 380 GB di dati. Un solo segmento, un solo tablespace, nessuna partizione. Un monolite.\nGli indici c\u0026rsquo;erano: uno sulla primary key, uno su data_movimento, uno composito su (cod_cliente, data_movimento). Ma quando la tabella supera una certa dimensione, anche un index range scan non basta più, perché il volume di dati restituito è comunque enorme.\nI sintomi: non è lentezza, è collasso #I problemi non si sono presentati tutti insieme. Sono arrivati gradualmente, come succede sempre con le tabelle che crescono senza controllo.\nPrimo segnale: i report mensili. La query di fatturazione aggregata — che sommava gli importi per cliente per un dato mese — era passata da 20 minuti a 4 ore nell\u0026rsquo;arco di un anno. L\u0026rsquo;execution plan mostrava un index range scan sulla data, ma il numero di blocchi letti era mostruoso: Oracle doveva attraversare centinaia di migliaia di leaf block dell\u0026rsquo;indice e poi fare le table access by rowid per recuperare le colonne non coperte.\nSecondo segnale: la manutenzione. L\u0026rsquo;ALTER INDEX REBUILD sull\u0026rsquo;indice della data richiedeva sei ore. Le statistiche (DBMS_STATS.GATHER_TABLE_STATS) non terminavano in una notte. I backup RMAN erano diventati una roulette: a volte entravano nella finestra, a volte no.\nTerzo segnale: i full table scan involontari. Query con predicati sulla data che l\u0026rsquo;optimizer decideva di risolvere con un full table scan perché il costo stimato dell\u0026rsquo;index scan era superiore. Su 380 GB di dati.\nL\u0026rsquo;execution plan della query di fatturazione era questo:\nSELECT cod_cliente, TRUNC(data_movimento, \u0026#39;MM\u0026#39;) AS mese, SUM(importo) AS totale FROM txn_movimenti WHERE data_movimento BETWEEN DATE \u0026#39;2025-01-01\u0026#39; AND DATE \u0026#39;2025-01-31\u0026#39; AND stato = \u0026#39;CON\u0026#39; GROUP BY cod_cliente, TRUNC(data_movimento, \u0026#39;MM\u0026#39;); --------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost | --------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 125K | 890K | | 1 | HASH GROUP BY | | 125K | 890K | | 2 | TABLE ACCESS BY INDEX ROWID| TXN_MOVIMENTI | 28M | 885K | |* 3 | INDEX RANGE SCAN | IDX_TXN_DATA | 28M | 85K | --------------------------------------------------------------------- 28 milioni di righe solo per gennaio. L\u0026rsquo;indice trovava le righe, ma poi Oracle doveva andare a pescare ogni singola riga dalla tabella per leggere cod_cliente, importo e stato. Milioni di random I/O su una tabella da 380 GB sparsa su migliaia di blocchi.\nLa soluzione: non serve un indice migliore, serve una struttura diversa #Ho passato due giorni ad analizzare i pattern di accesso prima di proporre qualsiasi soluzione. Perché il partitioning non è una bacchetta magica — se sbagli la chiave di partizione, peggiori le cose.\nI pattern erano chiari:\nIl 90% delle query aveva un predicato sulla data (data_movimento) I report erano sempre mensili o trimestrali Le query operative (singolo cliente) usavano sempre cod_cliente + data_movimento I dati oltre i 3 anni non venivano mai letti dai report, solo dai batch annuali di archiviazione La scelta è caduta su un interval partitioning mensile sulla colonna data_movimento. Non range partitioning classico, dove devi creare manualmente ogni partizione futura. Interval: definisci l\u0026rsquo;intervallo una volta e Oracle crea le partizioni automaticamente quando arrivano dati per un nuovo periodo.\nL\u0026rsquo;implementazione: CTAS, indici locali e zero downtime (quasi) #Non puoi fare ALTER TABLE ... PARTITION BY su una tabella esistente con 2 miliardi di righe. Non in Oracle 19c, almeno non senza l\u0026rsquo;opzione Online Table Redefinition. E quella opzione, su una tabella di queste dimensioni, ha i suoi rischi.\nHo scelto l\u0026rsquo;approccio CTAS — Create Table As Select — con parallelismo. Creare la nuova tabella partizionata, copiarci i dati, rinominare.\nStep 1: creare la tabella partizionata #CREATE TABLE txn_movimenti_part PARTITION BY RANGE (data_movimento) INTERVAL (NUMTOYMINTERVAL(1, \u0026#39;MONTH\u0026#39;)) ( PARTITION p_before_2016 VALUES LESS THAN (DATE \u0026#39;2016-01-01\u0026#39;), PARTITION p_2016_01 VALUES LESS THAN (DATE \u0026#39;2016-02-01\u0026#39;), PARTITION p_2016_02 VALUES LESS THAN (DATE \u0026#39;2016-03-01\u0026#39;) -- Oracle creerà automaticamente le partizioni successive ) TABLESPACE ts_billing_data NOLOGGING PARALLEL 8 AS SELECT /*+ PARALLEL(t, 8) */ txn_id, data_movimento, cod_cliente, tipo_movimento, importo, canale, stato, data_insert FROM txn_movimenti t; Il `NOLOGGING` è fondamentale: senza di esso la copia genera redo log per ogni blocco scritto. Su 380 GB significherebbe riempire l\u0026rsquo;area di redo e mandare in archivelog il sistema per giorni. Con NOLOGGING la copia è andata in 3 ore e mezza con parallelismo a 8.\nOvviamente dopo la copia ho rimesso il logging:\nALTER TABLE txn_movimenti_part LOGGING; E ho lanciato un backup RMAN immediatamente, perché i segmenti NOLOGGING non sono recuperabili in caso di restore.\nStep 2: indici locali #La scelta degli indici su una tabella partizionata è diversa da una tabella normale. Il concetto chiave è: indice locale vs indice globale.\nUn indice **locale** è partizionato con la stessa chiave della tabella. Ogni partizione della tabella ha la sua partizione di indice corrispondente. Vantaggio: le operazioni di manutenzione su una partizione non toccano le altre.\nUn indice globale copre tutte le partizioni. È più efficiente per query che non filtrano sulla chiave di partizione, ma qualsiasi operazione DDL sulla partizione (drop, truncate, split) invalida l\u0026rsquo;indice intero.\n-- Primary key come indice globale (serve per lookup puntuali) ALTER TABLE txn_movimenti_part ADD CONSTRAINT pk_txn_mov_part PRIMARY KEY (txn_id) USING INDEX GLOBAL; -- Indice locale sulla data (partition-aligned) CREATE INDEX idx_txn_mov_data ON txn_movimenti_part (data_movimento) LOCAL PARALLEL 8; -- Indice locale composito per le query operative CREATE INDEX idx_txn_mov_cli_data ON txn_movimenti_part (cod_cliente, data_movimento) LOCAL PARALLEL 8; La primary key resta globale perché le query per txn_id non includono mai la data — serve un accesso diretto. Gli altri indici sono locali perché allineati con il pattern d\u0026rsquo;uso: query per data, query per cliente+data.\nStep 3: lo switch #-- Rinominare la tabella originale (backup) ALTER TABLE txn_movimenti RENAME TO txn_movimenti_old; -- Rinominare la nuova tabella ALTER TABLE txn_movimenti_part RENAME TO txn_movimenti; -- Ricostruire i sinonimi se presenti -- Ricompilare gli oggetti invalidati BEGIN FOR obj IN (SELECT object_name, object_type FROM dba_objects WHERE status = \u0026#39;INVALID\u0026#39; AND owner = \u0026#39;BILLING\u0026#39;) LOOP BEGIN IF obj.object_type = \u0026#39;PACKAGE BODY\u0026#39; THEN EXECUTE IMMEDIATE \u0026#39;ALTER PACKAGE billing.\u0026#39; || obj.object_name || \u0026#39; COMPILE BODY\u0026#39;; ELSIF obj.object_type IN (\u0026#39;PROCEDURE\u0026#39;,\u0026#39;FUNCTION\u0026#39;,\u0026#39;VIEW\u0026#39;) THEN EXECUTE IMMEDIATE \u0026#39;ALTER \u0026#39; || obj.object_type || \u0026#39; billing.\u0026#39; || obj.object_name || \u0026#39; COMPILE\u0026#39;; END IF; EXCEPTION WHEN OTHERS THEN NULL; END; END LOOP; END; / Il downtime effettivo è stato il tempo dei due ALTER TABLE RENAME: qualche secondo. Tutto il resto — la copia dei dati, la creazione degli indici — è avvenuto in parallelo con il sistema attivo.\nStep 4: raccogliere le statistiche #BEGIN DBMS_STATS.GATHER_TABLE_STATS( ownname =\u0026gt; \u0026#39;BILLING\u0026#39;, tabname =\u0026gt; \u0026#39;TXN_MOVIMENTI\u0026#39;, granularity =\u0026gt; \u0026#39;ALL\u0026#39;, estimate_percent =\u0026gt; DBMS_STATS.AUTO_SAMPLE_SIZE, degree =\u0026gt; 8 ); END; / Il parametro granularity =\u0026gt; 'ALL' è importante: dice a Oracle di raccogliere statistiche a livello globale, di partizione e di subpartizione. Senza questo, l\u0026rsquo;optimizer potrebbe prendere decisioni sbagliate perché non conosce la distribuzione dei dati dentro le singole partizioni.\nPrima e dopo: i numeri #La stessa query di fatturazione, dopo il partitioning:\n------------------------------------------------------------------------ | Id | Operation | Name | Rows | Cost | ------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 125K | 12K | | 1 | HASH GROUP BY | | 125K | 12K | | 2 | PARTITION RANGE SINGLE | | 28M | 11K | | 3 | TABLE ACCESS FULL | TXN_MOVIMENTI | 28M | 11K | ------------------------------------------------------------------------ Guardate l\u0026rsquo;operazione al passo 2: PARTITION RANGE SINGLE. Oracle sa che i dati di gennaio stanno in una sola partizione e legge solo quella. Il full table scan che prima terrorizzava è ora un full partition scan — su circa 4 GB invece di 380.\nMetrica Prima Dopo Variazione Tempo query mensile 4 ore 3 minuti -98% Consistent gets 48M 580K -98.8% Physical reads 12M 95K -99.2% Tempo GATHER_TABLE_STATS 14 ore 25 min (per partizione) -97% Tempo rebuild indice 6 ore 12 min (per partizione) -97% Spazio backup incrementale 380 GB ~4 GB/mese -99% Il costo è passato da 890K a 12K. Non è un miglioramento percentuale — è un ordine di grandezza diverso.\nPartition pruning: la vera magia #Il meccanismo che rende tutto questo possibile si chiama **partition pruning** . Non è qualcosa che devi configurare — Oracle lo fa automaticamente quando il predicato della query corrisponde alla chiave di partizione.\nMa devi sapere quando funziona e quando no.\nFunziona con predicati diretti sulla colonna di partizione:\n-- Pruning attivo: Oracle legge solo la partizione di gennaio WHERE data_movimento BETWEEN DATE \u0026#39;2025-01-01\u0026#39; AND DATE \u0026#39;2025-01-31\u0026#39; -- Pruning attivo: Oracle legge solo la partizione specifica WHERE data_movimento = DATE \u0026#39;2025-03-15\u0026#39; Non funziona quando la colonna è dentro una funzione:\n-- Pruning DISATTIVATO: Oracle deve leggere tutte le partizioni WHERE TRUNC(data_movimento) = DATE \u0026#39;2025-01-01\u0026#39; -- Pruning DISATTIVATO: funzione sulla colonna WHERE TO_CHAR(data_movimento, \u0026#39;YYYY-MM\u0026#39;) = \u0026#39;2025-01\u0026#39; -- Pruning DISATTIVATO: espressione aritmetica WHERE data_movimento + 30 \u0026gt; SYSDATE Questo è l\u0026rsquo;errore più comune che vedo dopo un\u0026rsquo;implementazione di partitioning: gli sviluppatori applicano funzioni alla colonna di data senza rendersi conto che stanno disabilitando il pruning. E la tabella torna a essere letta per intero.\nHo dedicato mezza giornata a fare una review di tutte le query dell\u0026rsquo;applicazione che toccavano TXN_MOVIMENTI. Ne ho trovate undici con TRUNC(data_movimento) nel WHERE. Undici query che avrebbero ignorato il partitioning.\nLa gestione del ciclo di vita: drop partition #Uno dei vantaggi più concreti del partitioning è la gestione del ciclo di vita dei dati. Prima del partitioning, archiviare i dati vecchi significava un DELETE da miliardi di righe — operazione che generava montagne di redo e undo, bloccava la tabella per ore e rischiava di far esplodere il tablespace di undo.\nCon il partitioning:\n-- Archiviare i dati del 2016 su un tablespace read-only ALTER TABLE txn_movimenti MOVE PARTITION p_2016_01 TABLESPACE ts_archive; -- Oppure, se i dati non servono più ALTER TABLE txn_movimenti DROP PARTITION p_2016_01; Un DROP PARTITION su una partizione da 4 GB richiede meno di un secondo. Non genera undo. Non genera redo significativo. Non blocca le altre partizioni. È un\u0026rsquo;operazione DDL, non DML.\nHo impostato un job mensile che spostava le partizioni più vecchie di 5 anni nel tablespace di archivio e le metteva in read-only. Il cliente ha recuperato 120 GB di spazio attivo senza cancellare un singolo dato.\nCosa ho imparato (e gli errori da evitare) #Dopo quindici anni di partitioning Oracle, ho una lista di cose che vorrei aver saputo prima.\nLa chiave di partizione deve corrispondere al pattern di accesso. Sembra ovvio, ma ho visto tabelle partizionate per cod_cliente quando il 95% delle query filtra per data. Il partitioning funziona solo se le query possono fare pruning.\nInterval partitioning è quasi sempre meglio di range statico. Con il range classico devi creare manualmente le partizioni future, il che significa un job schedulato o un DBA che se lo ricorda. Con interval Oracle le crea da solo. Un problema in meno.\nGli indici globali sono una trappola. Funzionano bene per le query, ma qualsiasi operazione DDL sulla partizione li invalida. E ricostruire un indice globale su 2 miliardi di righe richiede ore. Usa indici locali dove possibile e accetta il compromesso.\nNOLOGGING non è opzionale per le operazioni bulk. Senza NOLOGGING, un CTAS di 380 GB genera altrettanti redo. Il tuo archivelog si riempirà, il database andrà in wait, e il DBA di turno riceverà una chiamata alle 3 di notte.\nTesta il pruning prima di andare in produzione. Non fidarti: verifica con EXPLAIN PLAN che ogni query critica faccia effettivamente pruning. Una singola TRUNC() nel predicato sbagliato e hai 380 GB di full table scan.\nIl partitioning non sostituisce gli indici. Riduce il volume di dati da esaminare, ma dentro la partizione hai ancora bisogno degli indici giusti. Una partizione mensile da 28 milioni di righe senza indice è comunque un problema.\nQuando hai bisogno del partitioning #Non tutte le tabelle hanno bisogno di partitioning. La mia regola empirica:\nSotto i 10 milioni di righe: probabilmente no Tra 10 e 100 milioni: dipende dal pattern di accesso e dalla crescita Sopra i 100 milioni: probabilmente sì Sopra il miliardo: non hai scelta Ma il momento giusto per implementarlo è prima che diventi urgente. Quando la tabella ha già 2 miliardi di righe, la migrazione è un progetto a sé. Quando ne ha 50 milioni e sta crescendo, è un\u0026rsquo;operazione da un pomeriggio.\nIl mio errore più grande con il partitioning? Non averlo proposto sei mesi prima, quando i segnali c\u0026rsquo;erano già tutti.\nGlossario #Partition Pruning — Meccanismo automatico di Oracle che esclude le partizioni non rilevanti durante l\u0026rsquo;esecuzione di una query, leggendo solo quelle che contengono dati corrispondenti al predicato.\nCTAS — Create Table As Select: tecnica per creare una nuova tabella popolandola con una SELECT in un\u0026rsquo;unica operazione. Fondamentale per migrare tabelle di miliardi di righe al partitioning.\nLocal Index — Indice partizionato con la stessa chiave della tabella. Ogni partizione ha la sua porzione di indice, rendendo le operazioni DDL indipendenti tra partizioni.\nNOLOGGING — Modalità Oracle che sopprime la generazione di redo log durante operazioni bulk, riducendo i tempi da giorni a ore. Richiede backup RMAN immediato dopo l\u0026rsquo;uso.\nTablespace — Unità logica di storage Oracle che raggruppa datafile fisici. Nel partitioning, permette di spostare partizioni vecchie su storage di archivio e gestire il ciclo di vita dei dati.\n","date":"23 dicembre 2025","permalink":"https://ivanluminaria.com/it/posts/oracle/oracle-partitioning/","section":"Database Strategy","summary":"\u003cp\u003eDue miliardi di righe. Non è un numero che si raggiunge in un giorno. Ci vogliono anni di transazioni, di movimenti, di registrazioni quotidiane che si accumulano. E per tutto quel tempo il database funziona, le query rispondono, i report escono. Poi un giorno qualcuno apre un ticket: \u0026ldquo;il report mensile ci mette quattro ore.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eQuattro ore. Per un report che sei mesi prima ne impiegava venti minuti.\u003c/p\u003e\n\u003cp\u003eNon è un bug. Non è un problema di rete o di storage lento. È la fisica dei dati: quando una tabella cresce oltre una certa soglia, gli approcci che funzionavano smettono di funzionare. E se non hai progettato la struttura per gestire quella crescita, il database fa l\u0026rsquo;unica cosa che può fare: leggere tutto.\u003c/p\u003e","title":"Oracle Partitioning: quando 2 miliardi di righe non entrano più in una query"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/architecture/","section":"Tags","summary":"","title":"Architecture"},{"content":"Il cliente era una media azienda nel settore assicurativo. Trecento dipendenti, un gestionale interno che girava su Oracle 19c, un solo server fisico in sala macchine al piano terra della sede. Nessuna replica. Nessuno standby. Nessun piano di disaster recovery.\nPer cinque anni aveva funzionato tutto. E quando le cose funzionano, nessuno vuole spendere soldi per proteggersi da problemi che non si sono mai visti.\nIl giorno in cui si è fermato tutto #Un mercoledì mattina di novembre, alle 8:47, il disco del gruppo dati principale ha avuto un guasto fisico. Non un errore logico, non una corruzione recuperabile. Un guasto hardware. Il controller RAID ha perso due dischi contemporaneamente — uno già degradato da settimane senza che nessuno se ne accorgesse, l\u0026rsquo;altro ceduto di colpo.\nIl database si è fermato. Le policy non si emettevano. I sinistri non si lavoravano. Il call center rispondeva ai clienti dicendo \u0026ldquo;problemi tecnici, richiamate più tardi.\u0026rdquo;\nHo ricevuto la chiamata alle 9:15. Quando sono arrivato in sede, il sistemista stava già cercando dischi compatibili. Li ha trovati nel primo pomeriggio. Tra sostituzione, rebuild del RAID e recovery del database dal backup della notte precedente, il sistema è tornato operativo alle 15:20.\nSei ore e mezza di fermo totale. E la perdita di tutte le transazioni dalle 23:00 della sera prima alle 8:47 del mattino — circa dieci ore di dati, perché il backup era solo notturno e gli archived log non venivano copiati su un\u0026rsquo;altra macchina.\nIl CEO quella sera ha mandato una mail a tutta l\u0026rsquo;azienda. Il giorno dopo mi ha chiamato: \u0026ldquo;Cosa dobbiamo fare perché non succeda mai più?\u0026rdquo;\nIl disegno #La risposta era semplice nel concetto, meno nella realizzazione: serviva un secondo database, sincronizzato in tempo reale, pronto a prendere il posto del primario in caso di guasto.\nOracle Active Data Guard fa esattamente questo. Un database primario che genera redo log , e uno standby che li riceve e li applica continuamente. Se il primario muore, lo standby diventa primario. Se tutto va bene, lo standby si può anche usare in sola lettura — per report, per backup, per alleggerire il carico.\nHo disegnato un\u0026rsquo;architettura a due nodi:\nPrimario (oraprod1): il server esistente, con i dischi nuovi, nella sede principale Standby (oraprod2): un nuovo server identico, nel data center del provider di hosting, a 12 km di distanza La scelta della distanza non era casuale. Abbastanza lontano da sopravvivere a un evento localizzato (incendio, allagamento, blackout prolungato), abbastanza vicino da permettere la replica sincrona senza latenza percepibile.\nLa configurazione #Preparazione del primario #Il primo passo è stato verificare che il primario fosse in ARCHIVELOG mode e con FORCE LOGGING attivo. Senza questi due prerequisiti, Data Guard non ha niente da replicare.\n-- Verifica archivelog mode SELECT log_mode FROM v$database; -- Se necessario, attivare SHUTDOWN IMMEDIATE; STARTUP MOUNT; ALTER DATABASE ARCHIVELOG; ALTER DATABASE OPEN; -- Force logging: impedisce operazioni NOLOGGING ALTER DATABASE FORCE LOGGING; Il FORCE LOGGING è fondamentale. Senza di esso, qualsiasi operazione con clausola NOLOGGING — un CREATE TABLE AS SELECT, un ALTER INDEX REBUILD — non genera redo e crea buchi nella replica. L\u0026rsquo;ho visto succedere tre volte in carriera. La terza volta ho deciso che FORCE LOGGING si attiva sempre, senza eccezioni.\nStandby redo log #Sul primario ho creato gli standby redo log — gruppi dedicati che verranno usati quando (e se) questo server diventerà standby a seguito di uno switchover.\n-- Standby redo log: n+1 rispetto ai redo log online -- Se hai 3 gruppi online, crei 4 standby ALTER DATABASE ADD STANDBY LOGFILE GROUP 4 SIZE 200M; ALTER DATABASE ADD STANDBY LOGFILE GROUP 5 SIZE 200M; ALTER DATABASE ADD STANDBY LOGFILE GROUP 6 SIZE 200M; ALTER DATABASE ADD STANDBY LOGFILE GROUP 7 SIZE 200M; La regola è n+1: se il primario ha tre gruppi di redo log, lo standby ne vuole quattro. Non è documentata in modo chiarissimo, ma l\u0026rsquo;ho imparata a spese mie — con tre gruppi uguali, sotto carico pesante lo standby può andare in stallo aspettando un gruppo libero.\nConfigurazione di rete #Il tnsnames.ora su entrambi i nodi deve conoscere sia il primario che lo standby. La configurazione è simmetrica:\nORAPROD1 = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.1)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = oraprod) ) ) ORAPROD2 = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.0.5.1)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = oraprod) ) ) Il listener.ora sullo standby deve includere un\u0026rsquo;entry statica per il database, perché durante il restore lo standby non è ancora aperto e il listener non può registrarlo dinamicamente:\nSID_LIST_LISTENER = (SID_LIST = (SID_DESC = (GLOBAL_DBNAME = oraprod_DGMGRL) (ORACLE_HOME = /u01/app/oracle/product/19c) (SID_NAME = oraprod) ) ) Il suffisso _DGMGRL serve al Data Guard Broker per identificare l\u0026rsquo;istanza. Senza questa entry statica, il broker non riesce a connettersi allo standby e le operazioni di switchover falliscono con errori criptici che ti fanno perdere mezza giornata.\nCreazione dello standby #Per la copia iniziale del database ho usato un DUPLICATE via RMAN attraverso la rete. Nessun backup su nastro, nessun trasferimento manuale di file. Diretto, dal primario allo standby:\n-- Sul server standby, avviare l\u0026#39;istanza in NOMOUNT STARTUP NOMOUNT PFILE=\u0026#39;/u01/app/oracle/product/19c/dbs/initoraprod.ora\u0026#39;; -- Da RMAN, connesso a entrambi RMAN TARGET sys/password@ORAPROD1 AUXILIARY sys/password@ORAPROD2 DUPLICATE TARGET DATABASE FOR STANDBY FROM ACTIVE DATABASE DORECOVER SPFILE SET db_unique_name=\u0026#39;oraprod_stby\u0026#39; SET log_archive_dest_2=\u0026#39;\u0026#39; SET fal_server=\u0026#39;ORAPROD1\u0026#39; NOFILENAMECHECK; Il NOFILENAMECHECK serve quando i path dei file sono identici su entrambe le macchine — stessa struttura di directory, stessa naming convention. Se i path differiscono, servono i parametri DB_FILE_NAME_CONVERT e LOG_FILE_NAME_CONVERT.\nLa copia ha richiesto circa tre ore per 400 GB attraverso una linea dedicata a 1 Gbps. Non velocissima, ma è un\u0026rsquo;operazione che si fa una volta sola.\nData Guard Broker #Il Broker è il componente che gestisce la configurazione Data Guard in modo centralizzato e consente lo switchover con un singolo comando. Senza il Broker puoi fare tutto a mano, ma non vuoi farlo a mano quando il primario è appena caduto e il CEO ti sta chiamando ogni cinque minuti.\n-- Sul primario ALTER SYSTEM SET dg_broker_start=TRUE; -- Sullo standby ALTER SYSTEM SET dg_broker_start=TRUE; Poi, da DGMGRL sul primario:\nDGMGRL\u0026gt; CREATE CONFIGURATION dg_config AS PRIMARY DATABASE IS oraprod CONNECT IDENTIFIER IS ORAPROD1; DGMGRL\u0026gt; ADD DATABASE oraprod_stby AS CONNECT IDENTIFIER IS ORAPROD2 MAINTAINED AS PHYSICAL; DGMGRL\u0026gt; ENABLE CONFIGURATION; A quel punto, SHOW CONFIGURATION deve restituire:\nConfiguration - dg_config Protection Mode: MaxPerformance Members: oraprod - Primary database oraprod_stby - Physical standby database Fast-Start Failover: DISABLED Configuration Status: SUCCESS La parola che vuoi vedere è SUCCESS. Qualsiasi altra cosa significa che c\u0026rsquo;è un problema di rete, di configurazione o di permessi da risolvere prima di andare avanti.\nIl primo switchover #Due settimane dopo il go-live dell\u0026rsquo;architettura, ho fatto il primo test di switchover. Di sabato mattina, con il gestionale chiuso, ma con il CEO presente — voleva vedere con i suoi occhi.\nDGMGRL\u0026gt; SWITCHOVER TO oraprod_stby; Un solo comando. Quarantadue secondi. Il primario è diventato standby, lo standby è diventato primario. Le applicazioni, configurate con il servizio corretto, si sono riconnesse automaticamente.\nDGMGRL\u0026gt; SHOW CONFIGURATION; Configuration - dg_config Protection Mode: MaxPerformance Members: oraprod_stby - Primary database oraprod - Physical standby database Fast-Start Failover: DISABLED Configuration Status: SUCCESS Poi abbiamo fatto lo switchback — ritorno al primario originale. Altri trentotto secondi. Tutto pulito.\nIl CEO ha guardato lo schermo, ha guardato me, e ha detto: \u0026ldquo;Quarantadue secondi contro sei ore. Perché non l\u0026rsquo;abbiamo fatto prima?\u0026rdquo;\nLa risposta non gliel\u0026rsquo;ho data. La sapevamo entrambi.\nQuello che non ti dicono #La configurazione che ho descritto funziona. Ma ci sono cose che la documentazione Oracle non enfatizza abbastanza.\nIl gap di rete. La replica sincrona (SYNC) garantisce zero data loss ma introduce latenza su ogni commit. Con 12 km e una buona fibra, la latenza aggiunta era di 1-2 millisecondi — accettabile. Ma a 100 km sarebbe stata 5-8 ms, e su un\u0026rsquo;applicazione con migliaia di commit al secondo il rallentamento si sarebbe sentito. Per questo ho scelto la modalità MaxPerformance (asincrona) come default, accettando la possibilità teorica di perdere qualche secondo di transazioni in caso di disastro totale. Per quel cliente, perdere cinque secondi di dati era infinitamente meglio di perderne dieci ore.\nIl password file. Il password file dell\u0026rsquo;utente SYS deve essere identico su primario e standby. Se lo cambi su uno e non sull\u0026rsquo;altro, il redo transport si blocca silenziosamente. Nessun errore evidente, solo un gap che cresce. L\u0026rsquo;ho scoperto dopo un\u0026rsquo;ora di debugging una domenica sera.\nI temp tablespace. Lo standby non replica i tablespace temporanei. Se apri lo standby in lettura per i report (Active Data Guard), devi creare manualmente i temp tablespace, altrimenti le query con sort o hash join falliscono con errori che non c\u0026rsquo;entrano niente con il vero problema.\n-- Sullo standby aperto in read-only ALTER TABLESPACE TEMP ADD TEMPFILE SIZE 2G AUTOEXTEND ON; I patch. Primario e standby devono avere lo stesso livello di patch. Se applichi una PSU al primario senza applicarla allo standby, il redo potrebbe contenere strutture che lo standby non sa interpretare. Il switchover funzionerà, ma dopo potresti avere corruzioni silenziose. La procedura corretta è: patch allo standby prima, switchover, patch al vecchio primario (ora standby), switchback.\nI numeri #A sei mesi dall\u0026rsquo;implementazione, il bilancio era chiaro:\nMetrica Prima Dopo RPO (Recovery Point Objective) ~10 ore (backup notturno) \u0026lt; 5 secondi RTO (Recovery Time Objective) 6+ ore (restore da backup) \u0026lt; 1 minuto (switchover) Disponibilità report in parallelo No Sì (Active Data Guard) Costo infrastruttura aggiuntiva — 1 server + linea dedicata Test di switchover eseguiti 0 6 (uno al mese) Il costo totale del progetto — server, licenze, linea dedicata, implementazione — era circa un quarto di quanto era costata quella singola giornata di fermo. Non in termini tecnici. In termini di polizze non emesse, sinistri non lavorati, clienti non serviti.\nQuello che ho imparato #Il disaster recovery non è un problema tecnico. È un problema di percezione del rischio. Finché il database funziona, il DR è una spesa. Quando il database si ferma, il DR è un investimento che si doveva fare sei mesi prima.\nNon puoi convincere un CEO con un disegno architetturale. Puoi solo aspettare che il disastro succeda e poi essere pronto con la soluzione. È cinico, ma è così che funziona nel novanta per cento dei casi.\nL\u0026rsquo;unica cosa che puoi fare prima è documentare il rischio, mettere per iscritto che l\u0026rsquo;hai segnalato, e tenere pronto il progetto nel cassetto. Io quel progetto l\u0026rsquo;avevo proposto diciotto mesi prima. Era stato accantonato con un \u0026ldquo;ne riparliamo l\u0026rsquo;anno prossimo.\u0026rdquo;\nL\u0026rsquo;anno prossimo è arrivato un mercoledì mattina di novembre, alle 8:47.\nGlossario #Data Guard — Tecnologia Oracle per la replica in tempo reale di un database su uno o più server standby. Lo standby riceve e applica continuamente i redo log del primario, permettendo switchover in pochi secondi.\nRedo Log — File di log in cui Oracle registra ogni modifica ai dati prima di scriverla nei datafile. Sono la base del recovery e della replica Data Guard: senza redo, nessuna di queste operazioni è possibile.\nRPO — Recovery Point Objective. La quantità massima di dati che un\u0026rsquo;organizzazione può permettersi di perdere in caso di disastro, misurata in tempo. Con Data Guard asincrono si riducono a pochi secondi.\nRTO — Recovery Time Objective. Il tempo massimo accettabile per ripristinare il servizio dopo un guasto. Con Data Guard e switchover automatico, si passa da ore a meno di un minuto.\nRMAN — Recovery Manager. Strumento nativo Oracle per backup, restore e recovery, inclusa la creazione di database standby via DUPLICATE ... FOR STANDBY FROM ACTIVE DATABASE.\n","date":"16 dicembre 2025","permalink":"https://ivanluminaria.com/it/posts/oracle/oracle-data-guard/","section":"Database Strategy","summary":"\u003cp\u003eIl cliente era una media azienda nel settore assicurativo. Trecento dipendenti, un gestionale interno che girava su Oracle 19c, un solo server fisico in sala macchine al piano terra della sede. Nessuna replica. Nessuno standby. Nessun piano di disaster recovery.\u003c/p\u003e\n\u003cp\u003ePer cinque anni aveva funzionato tutto. E quando le cose funzionano, nessuno vuole spendere soldi per proteggersi da problemi che non si sono mai visti.\u003c/p\u003e\n\u003ch2 id=\"il-giorno-in-cui-si-è-fermato-tutto\" class=\"relative group\"\u003eIl giorno in cui si è fermato tutto \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#il-giorno-in-cui-si-%c3%a8-fermato-tutto\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn mercoledì mattina di novembre, alle 8:47, il disco del gruppo dati principale ha avuto un guasto fisico. Non un errore logico, non una corruzione recuperabile. Un guasto hardware. Il controller RAID ha perso due dischi contemporaneamente — uno già degradato da settimane senza che nessuno se ne accorgesse, l\u0026rsquo;altro ceduto di colpo.\u003c/p\u003e","title":"Da single instance a Data Guard: il giorno in cui il CEO ha capito il DR"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/data-guard/","section":"Tags","summary":"","title":"Data-Guard"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/disaster-recovery/","section":"Tags","summary":"","title":"Disaster-Recovery"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/switchover/","section":"Tags","summary":"","title":"Switchover"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/kimball/","section":"Tags","summary":"","title":"Kimball"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/scd/","section":"Tags","summary":"","title":"Scd"},{"content":"Il direttore commerciale si presenta alla riunione del lunedì mattina con una domanda semplice: \u0026ldquo;Quanti clienti avevamo nella regione Nord a giugno scorso?\u0026rdquo;\nRisposta del DWH: silenzio.\nNon perché il sistema fosse giù, o perché mancasse la tabella. Il dato c\u0026rsquo;era, tecnicamente. Ma era sbagliato. Il DWH rispondeva con i clienti che oggi sono nella regione Nord — non quelli che c\u0026rsquo;erano a giugno. Perché ogni notte, il processo di caricamento sovrascriveva l\u0026rsquo;anagrafica clienti con i dati correnti, cancellando ogni traccia di quello che c\u0026rsquo;era prima.\nUn cliente che a giugno era in regione Nord e a settembre si è spostato in regione Centro? Per il DWH, quel cliente è sempre stato in regione Centro. La storia non esiste.\nIl progetto e il modello originale #Il contesto era un data warehouse nel settore assicurativo — gestione sinistri e portafoglio clienti. Il sistema sorgente conteneva un\u0026rsquo;anagrafica con i dati di ogni cliente: nome, regione, agente di riferimento, classe di rischio, tipo di polizza.\nLa dimensione nel DWH era modellata così:\nCREATE TABLE dim_cliente ( cliente_id NUMBER(10) NOT NULL, nome VARCHAR2(100) NOT NULL, regione VARCHAR2(50) NOT NULL, agente VARCHAR2(100), classe_rischio VARCHAR2(20), tipo_polizza VARCHAR2(50), CONSTRAINT pk_dim_cliente PRIMARY KEY (cliente_id) ); L\u0026rsquo;ETL notturno era un semplice MERGE : se il cliente esiste, aggiorna tutti i campi; se non esiste, inserisci.\nMERGE INTO dim_cliente d USING stg_cliente s ON (d.cliente_id = s.cliente_id) WHEN MATCHED THEN UPDATE SET d.nome = s.nome, d.regione = s.regione, d.agente = s.agente, d.classe_rischio = s.classe_rischio, d.tipo_polizza = s.tipo_polizza WHEN NOT MATCHED THEN INSERT ( cliente_id, nome, regione, agente, classe_rischio, tipo_polizza ) VALUES ( s.cliente_id, s.nome, s.regione, s.agente, s.classe_rischio, s.tipo_polizza ); Semplice, pulito, veloce. E completamente sbagliato per un data warehouse.\nQuesto è quello che Kimball chiama SCD Tipo 1 — Slowly Changing Dimension di Tipo 1. Sovrascrivi il vecchio valore con il nuovo. Nessuna storia, nessun versioning. Il dato attuale cancella il dato precedente.\nPer un sistema OLTP è perfetto: vuoi sempre l\u0026rsquo;indirizzo corrente del cliente, il telefono aggiornato, la mail valida. Ma un data warehouse non è un sistema transazionale. Un data warehouse è una macchina del tempo. E una macchina del tempo che sovrascrive il passato è inutile.\nCosa si perde con la Tipo 1 #Il direttore commerciale non era l\u0026rsquo;unico a fare domande a cui il DWH non poteva rispondere. Ecco un campione delle richieste che si sono accumulate in tre mesi:\n\u0026ldquo;Quanti clienti sono passati dalla classe di rischio Alta alla Bassa nell\u0026rsquo;ultimo anno?\u0026rdquo; — Impossibile. La classe precedente non esiste più. \u0026ldquo;L\u0026rsquo;agente Rossi ha perso clienti rispetto al trimestre scorso?\u0026rdquo; — Impossibile. Se un cliente è stato riassegnato all\u0026rsquo;agente Bianchi, non c\u0026rsquo;è traccia che fosse mai stato dell\u0026rsquo;agente Rossi. \u0026ldquo;Il fatturato della regione Sud è calato o i clienti si sono spostati?\u0026rdquo; — Impossibile da distinguere. Se un cliente da 200K si è spostato dalla regione Sud alla regione Centro, il fatturato della regione Sud cala ma non perché il business vada male — semplicemente il cliente ha cambiato indirizzo. Ogni volta la risposta era la stessa: \u0026ldquo;Il sistema non tiene la storia.\u0026rdquo; Che tradotto in linguaggio business significa: \u0026ldquo;Non lo sappiamo.\u0026rdquo;\nA un certo punto il CFO ha chiesto un report di analisi trimestrale che confrontasse la composizione del portafoglio clienti tra Q1 e Q2. Il team di BI ha provato a costruirlo. Ci ha messo tre giorni. Il risultato era inaffidabile perché i dati di Q1 non c\u0026rsquo;erano più — erano stati sovrascritti dai dati di Q2. Il report confrontava Q2 con Q2 travestito da Q1.\nÈ stato quel momento che ha fatto scattare il progetto di ristrutturazione.\nSCD Tipo 2: il principio #La Tipo 2 non sovrascrive. Versiona.\nQuando un attributo cambia, il record corrente viene chiuso — gli si assegna una data di fine validità — e viene inserito un nuovo record con i valori aggiornati e una nuova data di inizio validità. Il vecchio record resta nel database, intatto, con tutti i valori che aveva quando era corrente.\nPer farlo servono tre elementi aggiuntivi nella tabella dimensionale:\nUna chiave surrogata — un identificativo generato dal DWH, distinto dalla chiave naturale del sistema sorgente. Serve perché lo stesso cliente avrà più record (uno per ogni versione), quindi la chiave naturale non è più univoca. Date di validità — valid_from e valid_to — che definiscono l\u0026rsquo;intervallo temporale in cui ogni versione del record era corrente. Un flag di versione corrente — is_current — che permette di recuperare rapidamente la versione attiva senza filtrare sulle date. La nuova tabella dimensionale #CREATE TABLE dim_cliente ( cliente_key NUMBER(10) NOT NULL, cliente_id NUMBER(10) NOT NULL, nome VARCHAR2(100) NOT NULL, regione VARCHAR2(50) NOT NULL, agente VARCHAR2(100), classe_rischio VARCHAR2(20), tipo_polizza VARCHAR2(50), valid_from DATE NOT NULL, valid_to DATE NOT NULL, is_current CHAR(1) DEFAULT \u0026#39;Y\u0026#39; NOT NULL, CONSTRAINT pk_dim_cliente PRIMARY KEY (cliente_key) ); CREATE INDEX idx_dim_cliente_natural ON dim_cliente (cliente_id, is_current); CREATE INDEX idx_dim_cliente_validity ON dim_cliente (cliente_id, valid_from, valid_to); CREATE SEQUENCE seq_dim_cliente START WITH 1 INCREMENT BY 1; La cliente_key è la chiave surrogata — generata dalla sequence, mai presa dal sistema sorgente. La cliente_id è la chiave naturale — serve per collegare le diverse versioni dello stesso cliente.\nLa valid_to per il record corrente la fisso a DATE '9999-12-31' — una convenzione standard che semplifica le query temporali. Quando cerchi il record valido a una certa data, il filtro WHERE data_riferimento BETWEEN valid_from AND valid_to funziona senza casi speciali.\nLa logica ETL #L\u0026rsquo;ETL della Tipo 2 ha due fasi: prima chiudi i record che sono cambiati, poi inserisci le nuove versioni. L\u0026rsquo;ordine è importante — se inserisci prima di chiudere, hai un momento in cui esistono due versioni \u0026ldquo;correnti\u0026rdquo; dello stesso cliente.\nFase 1: identificare e chiudere i record modificati #MERGE INTO dim_cliente d USING ( SELECT s.cliente_id, s.nome, s.regione, s.agente, s.classe_rischio, s.tipo_polizza FROM stg_cliente s JOIN dim_cliente d ON s.cliente_id = d.cliente_id AND d.is_current = \u0026#39;Y\u0026#39; WHERE (s.regione != d.regione OR s.agente != d.agente OR s.classe_rischio != d.classe_rischio OR s.tipo_polizza != d.tipo_polizza OR s.nome != d.nome) ) changed ON (d.cliente_id = changed.cliente_id AND d.is_current = \u0026#39;Y\u0026#39;) WHEN MATCHED THEN UPDATE SET d.valid_to = TRUNC(SYSDATE) - 1, d.is_current = \u0026#39;N\u0026#39;; Il WHERE confronta ogni attributo tracciato. Se anche uno solo è diverso, il record corrente viene chiuso: la valid_to viene impostata a ieri e is_current diventa \u0026lsquo;N\u0026rsquo;.\nUna nota pratica: il confronto con != non gestisce i NULL. Se agente può essere NULL, servono le funzioni di confronto NULL-safe. In Oracle uso DECODE:\nWHERE DECODE(s.regione, d.regione, 0, 1) = 1 OR DECODE(s.agente, d.agente, 0, 1) = 1 OR DECODE(s.classe_rischio, d.classe_rischio, 0, 1) = 1 -- ... DECODE tratta due NULL come uguali — esattamente il comportamento che serve.\nFase 2: inserire le nuove versioni #INSERT INTO dim_cliente ( cliente_key, cliente_id, nome, regione, agente, classe_rischio, tipo_polizza, valid_from, valid_to, is_current ) SELECT seq_dim_cliente.NEXTVAL, s.cliente_id, s.nome, s.regione, s.agente, s.classe_rischio, s.tipo_polizza, TRUNC(SYSDATE), DATE \u0026#39;9999-12-31\u0026#39;, \u0026#39;Y\u0026#39; FROM stg_cliente s WHERE NOT EXISTS ( SELECT 1 FROM dim_cliente d WHERE d.cliente_id = s.cliente_id AND d.is_current = \u0026#39;Y\u0026#39; ); Questa INSERT cattura due casi: i clienti completamente nuovi (che non esistono in dim_cliente) e i clienti la cui versione corrente è stata appena chiusa nella Fase 1 (che quindi non hanno più un record con is_current = 'Y').\nLa valid_from è la data di oggi. La valid_to è il \u0026ldquo;fine del tempo\u0026rdquo; — 9999-12-31. La cliente_key è generata dalla sequence.\nI dati: prima e dopo #Vediamo un esempio concreto. Il cliente 2001 — \u0026ldquo;Alfa Assicurazioni Srl\u0026rdquo; — è nella regione Nord, assegnato all\u0026rsquo;agente Rossi, classe di rischio Media.\nA luglio il cliente viene riassegnato all\u0026rsquo;agente Bianchi. A ottobre cambia classe di rischio da Media ad Alta.\nCon la Tipo 1 (il modello precedente), a ottobre la dim_cliente contiene una sola riga:\nCLIENTE_ID NOME REGIONE AGENTE CLASSE_RISCHIO ---------- ----------------------- ------- ------- -------------- 2001 Alfa Assicurazioni Srl Nord Bianchi Alta Nessuna traccia di Rossi. Nessuna traccia della classe Media. Per il DWH, questo cliente è sempre stato dell\u0026rsquo;agente Bianchi con classe Alta.\nCon la Tipo 2, a ottobre la dim_cliente contiene tre righe:\nKEY CLIENTE_ID NOME REGIONE AGENTE CLASSE VALID_FROM VALID_TO CURRENT ---- ---------- ----------------------- ------- ------- ------ ---------- ---------- ------- 1001 2001 Alfa Assicurazioni Srl Nord Rossi Media 2025-01-15 2025-07-09 N 1002 2001 Alfa Assicurazioni Srl Nord Bianchi Media 2025-07-10 2025-10-04 N 1003 2001 Alfa Assicurazioni Srl Nord Bianchi Alta 2025-10-05 9999-12-31 Y Tre versioni dello stesso cliente. Ogni versione racconta un pezzo della storia: chi era l\u0026rsquo;agente, quale era la classe di rischio, e in quale periodo. Le date non si sovrappongono. Il flag is_current identifica la versione attiva.\nLe query temporali #Ora il direttore commerciale può avere la sua risposta.\nQuanti clienti nella regione Nord a giugno? #SELECT COUNT(DISTINCT cliente_id) AS clienti_nord_giugno FROM dim_cliente WHERE regione = \u0026#39;Nord\u0026#39; AND DATE \u0026#39;2025-06-15\u0026#39; BETWEEN valid_from AND valid_to; La query è diretta: prendi tutti i record che erano validi il 15 giugno 2025 e filtra per regione. Nessun CASE WHEN, nessuna logica condizionale, nessuna approssimazione.\nClienti che hanno cambiato classe di rischio nell\u0026rsquo;ultimo anno #SELECT c1.cliente_id, c1.nome, c1.classe_rischio AS classe_precedente, c2.classe_rischio AS classe_attuale, c1.valid_to + 1 AS data_cambio FROM dim_cliente c1 JOIN dim_cliente c2 ON c1.cliente_id = c2.cliente_id AND c1.valid_to + 1 = c2.valid_from WHERE c1.classe_rischio != c2.classe_rischio AND c1.valid_to \u0026gt;= ADD_MONTHS(TRUNC(SYSDATE), -12) ORDER BY data_cambio DESC; Due versioni consecutive dello stesso cliente, unite per data di transizione. Se la classe di rischio è diversa tra le due versioni, il cliente ha cambiato classe. La data del cambio è il giorno dopo la chiusura della versione precedente.\nConfronto portafoglio Q1 vs Q2 #SELECT regione, COUNT(DISTINCT CASE WHEN DATE \u0026#39;2025-03-31\u0026#39; BETWEEN valid_from AND valid_to THEN cliente_id END) AS clienti_q1, COUNT(DISTINCT CASE WHEN DATE \u0026#39;2025-06-30\u0026#39; BETWEEN valid_from AND valid_to THEN cliente_id END) AS clienti_q2 FROM dim_cliente WHERE DATE \u0026#39;2025-03-31\u0026#39; BETWEEN valid_from AND valid_to OR DATE \u0026#39;2025-06-30\u0026#39; BETWEEN valid_from AND valid_to GROUP BY regione ORDER BY regione; Un singolo scan della tabella, due conteggi distinti filtrati per data. Il CFO ha il suo report trimestrale — quello vero, non quello che confrontava Q2 con sé stesso.\nLa fact table e le chiavi surrogate #Un punto che spesso viene sottovalutato: la fact table deve usare la chiave surrogata, non la chiave naturale.\nCREATE TABLE fact_sinistro ( sinistro_key NUMBER(10) NOT NULL, cliente_key NUMBER(10) NOT NULL, -- FK alla versione specifica data_key NUMBER(8) NOT NULL, importo NUMBER(15,2), tipo_sinistro VARCHAR2(50), CONSTRAINT pk_fact_sinistro PRIMARY KEY (sinistro_key), CONSTRAINT fk_fact_cliente FOREIGN KEY (cliente_key) REFERENCES dim_cliente (cliente_key) ); Il cliente_key nella fact punta alla versione del cliente che era corrente al momento del sinistro. Se un sinistro avviene a maggio, quando il cliente era ancora dell\u0026rsquo;agente Rossi, la fact punta alla versione con agente Rossi. Se un altro sinistro avviene a settembre, con il cliente ormai dell\u0026rsquo;agente Bianchi, la fact punta alla versione con agente Bianchi.\nIl risultato è che ogni fatto è associato al contesto dimensionale corretto per il momento in cui è accaduto. Se interroghi i sinistri di maggio, li vedi con l\u0026rsquo;agente Rossi. Se interroghi quelli di settembre, li vedi con l\u0026rsquo;agente Bianchi. Senza nessuna logica temporale nella query — il JOIN diretto tra fact e dimension restituisce il contesto giusto.\n-- Sinistri per agente, con il contesto corretto al momento del sinistro SELECT d.agente, COUNT(*) AS num_sinistri, SUM(f.importo) AS importo_totale FROM fact_sinistro f JOIN dim_cliente d ON f.cliente_key = d.cliente_key GROUP BY d.agente ORDER BY importo_totale DESC; Nessuna clausola temporale. Il JOIN sulla chiave surrogata fa tutto il lavoro.\nLe dimensioni della Tipo 2 #Il costo della Tipo 2 è la crescita della tabella dimensionale. Con la Tipo 1, ogni cliente è una riga. Con la Tipo 2, ogni cliente può avere N righe — una per ogni cambio di attributo tracciato.\nNel progetto assicurativo i numeri erano questi:\nMetrica Valore Clienti attivi ~120.000 Attributi tracciati 4 (regione, agente, classe rischio, tipo polizza) Tasso di cambio medio ~8% dei clienti/anno Righe dim_cliente dopo 1 anno ~140.000 Righe dim_cliente dopo 3 anni ~180.000 Righe dim_cliente dopo 5 anni ~220.000 Da 120K a 220K in cinque anni. Un aumento del 83% — che sembra tanto in percentuale ma è trascurabile in termini assoluti. 220K righe sono niente per Oracle. La query con indice sulla chiave surrogata resta nell\u0026rsquo;ordine dei millisecondi.\nIl problema si pone quando hai milioni di clienti con alti tassi di cambio. In quel caso monitori la crescita, consideri il partizionamento della dimensione, e sopratutto scegli con cura quali attributi tracciare. Non tutti gli attributi meritano la Tipo 2. Il numero di telefono del cliente? Tipo 1, sovrascrittura. La regione commerciale? Tipo 2, perché ha impatto sull\u0026rsquo;analisi del fatturato.\nLa scelta di quali attributi tracciare con Tipo 2 è una decisione di business, non tecnica. Chiedi al business: \u0026ldquo;Se questo campo cambia, vi serve sapere qual era il valore precedente?\u0026rdquo; Se la risposta è sì, è Tipo 2. Se è no, è Tipo 1.\nQuando non serve la Tipo 2 #Non tutte le dimensioni hanno bisogno della storia. Ho visto progetti in cui ogni dimensione era Tipo 2 \u0026ldquo;per sicurezza\u0026rdquo; — il risultato era un modello inutilmente complesso, ETL lenti, e nessuno che avesse mai interrogato la storia della dimensione \u0026ldquo;tipo_pagamento\u0026rdquo; o \u0026ldquo;canale_vendita\u0026rdquo;.\nLa Tipo 2 ha un costo: complessità dell\u0026rsquo;ETL, crescita della tabella, necessità di gestire le chiavi surrogate nella fact. È un costo che vale la pena pagare quando il business ha bisogno della storia. Se non ce l\u0026rsquo;ha, la Tipo 1 è la scelta giusta.\nCi sono anche casi in cui la Tipo 2 non basta. Se serve sapere non solo cosa è cambiato ma anche chi ha fatto il cambio e perché, allora serve un audit trail — una tabella separata con un log completo delle modifiche. La Tipo 2 traccia le versioni, non le cause.\nE per le dimensioni con cambiamenti molto frequenti — prezzi che cambiano ogni giorno, scoring che si aggiorna ogni ora — la Tipo 2 può generare una crescita insostenibile. In quei casi si valuta la Tipo 6 (una combinazione di Tipo 1, 2 e 3) o approcci mini-dimension.\nMa per il caso più comune — anagrafiche clienti, prodotti, dipendenti, punti vendita — la Tipo 2 è lo strumento giusto. Semplice abbastanza da implementare senza framework esotici, potente abbastanza da restituire al business la dimensione che gli mancava: il tempo.\nQuello che ho imparato #Il direttore commerciale non sapeva di avere bisogno della storia finché non gli è servita. E quando gli è servita, il DWH non ce l\u0026rsquo;aveva.\nQuesto è il punto. Non si implementa la Tipo 2 perché \u0026ldquo;è best practice\u0026rdquo; o perché \u0026ldquo;Kimball lo dice nel capitolo 5\u0026rdquo;. Si implementa perché un data warehouse senza storia è un database operativo con una star schema appiccicata sopra. Funziona per i report del mese corrente, ma non risponde alla domanda che prima o poi qualcuno farà: \u0026ldquo;Com\u0026rsquo;era prima?\u0026rdquo;\nLa domanda arriva sempre. La questione è se il tuo DWH è pronto a rispondere.\nGlossario #Chiave surrogata — Identificativo numerico generato dal data warehouse, distinto dalla chiave naturale del sistema sorgente. Nella SCD Tipo 2 è indispensabile perché lo stesso record può avere più versioni, e la chiave naturale non è più univoca.\nFact table — Tabella centrale dello star schema che contiene le misure numeriche (importi, quantità, conteggi) e le chiavi esterne verso le tabelle dimensionali. Ogni riga rappresenta un evento o una transazione di business.\nKimball — Ralph Kimball, autore della metodologia di progettazione data warehouse basata su dimensional modeling, star schema e processi ETL bottom-up. Il suo framework classifica le Slowly Changing Dimensions nei tipi da 0 a 7.\nMERGE — Istruzione SQL che combina INSERT e UPDATE in un\u0026rsquo;unica operazione: se il record esiste lo aggiorna, se non esiste lo inserisce. In Oracle è anche nota come \u0026ldquo;upsert\u0026rdquo; ed è il meccanismo base dell\u0026rsquo;ETL per le dimensioni SCD.\nStar schema — Modello di dati tipico del data warehouse: una fact table al centro collegata a più tabelle dimensionali tramite chiavi esterne. Semplifica le query analitiche e ottimizza le performance delle aggregazioni.\n","date":"11 novembre 2025","permalink":"https://ivanluminaria.com/it/posts/data-warehouse/scd-tipo-2/","section":"Database Strategy","summary":"\u003cp\u003eIl direttore commerciale si presenta alla riunione del lunedì mattina con una domanda semplice: \u0026ldquo;Quanti clienti avevamo nella regione Nord a giugno scorso?\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eRisposta del DWH: silenzio.\u003c/p\u003e\n\u003cp\u003eNon perché il sistema fosse giù, o perché mancasse la tabella. Il dato c\u0026rsquo;era, tecnicamente. Ma era sbagliato. Il DWH rispondeva con i clienti che \u003cem\u003eoggi\u003c/em\u003e sono nella regione Nord — non quelli che c\u0026rsquo;erano a giugno. Perché ogni notte, il processo di caricamento sovrascriveva l\u0026rsquo;anagrafica clienti con i dati correnti, cancellando ogni traccia di quello che c\u0026rsquo;era prima.\u003c/p\u003e","title":"SCD Tipo 2: la storia che il business non sapeva di volere"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/csv-export/","section":"Tags","summary":"","title":"Csv-Export"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/multi-instance/","section":"Tags","summary":"","title":"Multi-Instance"},{"content":"Il ticket diceva: \u0026ldquo;Serve un export CSV dalla tabella ordini del gestionale. Entro le 14.\u0026rdquo;\nErano le 11. Tre ore per una SELECT con INTO OUTFILE — roba da cinque minuti, pensavo. Poi ho aperto la VPN, mi sono collegato al server e ho capito che cinque minuti non sarebbero bastati.\nIl server era una macchina CentOS 7 con quattro istanze MySQL. Quattro. Sullo stesso host, con quattro servizi systemd diversi, quattro porte diverse, quattro socket Unix diverse, quattro directory dati diverse. Un setup che qualcuno aveva messo in piedi anni prima — probabilmente per risparmiare su un secondo server — e che da allora nessuno aveva più toccato né documentato.\nIl primo problema non era la query. Il primo problema era: a quale delle quattro istanze devo collegarmi?\nL\u0026rsquo;ambiente: quattro MySQL, un solo server #Ambienti multi-istanza su MySQL non sono rari come si potrebbe pensare. Li trovo più spesso di quanto vorrei, soprattutto in aziende medio-piccole dove i server sono pochi e le applicazioni sono tante. La logica è semplice: invece di comprare quattro server, ne compri uno potente e ci fai girare quattro istanze MySQL, ognuna con il suo database, la sua porta, il suo file di configurazione.\nIl risultato funziona, finché non devi fare manutenzione. E la manutenzione su un multi-istanza, senza documentazione, è un esercizio di archeologia informatica.\nSu quel server, la situazione era questa:\nsystemctl list-units --type=service | grep mysql mysqld.service loaded active running MySQL Server (porta 3306) mysqld-app2.service loaded active running MySQL Server (porta 3307) mysqld-reporting.service loaded active running MySQL Server (porta 3308) mysqld-legacy.service loaded active running MySQL Server (porta 3309) Quattro servizi. I nomi erano vagamente indicativi — \u0026ldquo;app2\u0026rdquo;, \u0026ldquo;reporting\u0026rdquo;, \u0026ldquo;legacy\u0026rdquo; — ma il ticket parlava del \u0026ldquo;gestionale\u0026rdquo; senza specificare quale istanza ospitasse quel database. Nessuna wiki interna, nessun file README sul server, nessun commento nei file di configurazione.\nTrovare l\u0026rsquo;istanza giusta #Il primo passo è stato capire quale istanza contenesse il database degli ordini. La tecnica è sempre la stessa: parti dal servizio systemd, risali al file di configurazione, da lì leggi porta e socket.\nsystemctl cat mysqld-app2.service | grep ExecStart ExecStart=/usr/sbin/mysqld --defaults-file=/etc/mysql/app2.cnf Ogni servizio puntava a un my.cnf diverso. Ho controllato tutti e quattro:\ngrep -E \u0026#34;^(port|socket|datadir)\u0026#34; /etc/mysql/app2.cnf port = 3307 socket = /var/run/mysqld/mysqld-app2.sock datadir = /data/mysql-app2 Per ciascuna istanza, ho annotato porta, socket e datadir. Poi ho fatto il giro rapido:\nmysql --socket=/var/run/mysqld/mysqld.sock -u root -p -e \u0026#34;SHOW DATABASES;\u0026#34; 2\u0026gt;/dev/null mysql --socket=/var/run/mysqld/mysqld-app2.sock -u root -p -e \u0026#34;SHOW DATABASES;\u0026#34; 2\u0026gt;/dev/null mysql --socket=/var/run/mysqld/mysqld-reporting.sock -u root -p -e \u0026#34;SHOW DATABASES;\u0026#34; 2\u0026gt;/dev/null mysql --socket=/var/run/mysqld/mysqld-legacy.sock -u root -p -e \u0026#34;SHOW DATABASES;\u0026#34; 2\u0026gt;/dev/null Il database gestionale_prod era sulla seconda istanza — quella sulla porta 3307 con socket /var/run/mysqld/mysqld-app2.sock.\nUn dettaglio che sembra banale ma che in un ambiente multi-istanza fa la differenza: quando ti colleghi a MySQL specificando solo -h localhost, il client non usa TCP. Usa il socket Unix di default, che quasi sempre è quello dell\u0026rsquo;istanza primaria sulla porta 3306. Se il database che cerchi sta su un\u0026rsquo;altra istanza, ti colleghi a quella sbagliata senza nemmeno accorgertene.\nLa connessione e la verifica #Una volta identificata l\u0026rsquo;istanza, mi sono collegato specificando esplicitamente il socket:\nmysql --socket=/var/run/mysqld/mysqld-app2.sock -u root -p Prima cosa dopo il login: verificare di essere sull\u0026rsquo;istanza giusta.\nSHOW VARIABLES LIKE \u0026#39;port\u0026#39;; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | port | 3307 | +---------------+-------+ SELECT DATABASE(); USE gestionale_prod; SHOW TABLES LIKE \u0026#39;%ordini%\u0026#39;; +----------------------------------+ | Tables_in_gestionale_prod | +----------------------------------+ | ordini | | ordini_dettaglio | | ordini_storico | +----------------------------------+ Porta 3307, database presente, tabella ordini al suo posto. La connessione era quella giusta.\nIl check sulla porta sembra paranoia, ma non lo è. In un ambiente con quattro istanze, confondere quale socket punta a quale porta è più facile di quanto si pensi. E l\u0026rsquo;errore lo scopri solo quando i dati che esporti non sono quelli che ti aspetti — o peggio, quando fai una modifica pensando di essere sul database di test e scopri che eri in produzione.\nIl primo tentativo: INTO OUTFILE #La query era semplice. Il richiedente voleva gli ordini dell\u0026rsquo;ultimo trimestre con importo, cliente e data:\nSELECT o.id_ordine, o.data_ordine, c.ragione_sociale, o.importo_totale FROM ordini o JOIN clienti c ON o.id_cliente = c.id_cliente WHERE o.data_ordine \u0026gt;= \u0026#39;2025-07-01\u0026#39; ORDER BY o.data_ordine; Il primo istinto è stato usare `INTO OUTFILE` , il modo nativo di MySQL per scrivere risultati su file:\nSELECT o.id_ordine, o.data_ordine, c.ragione_sociale, o.importo_totale FROM ordini o JOIN clienti c ON o.id_cliente = c.id_cliente WHERE o.data_ordine \u0026gt;= \u0026#39;2025-07-01\u0026#39; ORDER BY o.data_ordine INTO OUTFILE \u0026#39;/tmp/export_ordini.csv\u0026#39; FIELDS TERMINATED BY \u0026#39;,\u0026#39; ENCLOSED BY \u0026#39;\u0026#34;\u0026#39; LINES TERMINATED BY \u0026#39;\\n\u0026#39;; La risposta di MySQL è stata secca:\nERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement Ecco il muro.\nsecure-file-priv : la direttiva che blocca tutto (e fa bene) #La variabile secure_file_priv è il modo in cui MySQL limita le operazioni di lettura e scrittura su file. Controlla dove LOAD DATA INFILE, SELECT INTO OUTFILE e la funzione LOAD_FILE() possono operare.\nSHOW VARIABLES LIKE \u0026#39;secure_file_priv\u0026#39;; +------------------+------------------------+ | Variable_name | Value | +------------------+------------------------+ | secure_file_priv | /var/lib/mysql-files/ | +------------------+------------------------+ Questa variabile ha tre modalità:\nUn percorso specifico (es. /var/lib/mysql-files/): le operazioni su file funzionano, ma solo dentro quella directory Stringa vuota (\u0026quot;\u0026quot;): nessuna restrizione — MySQL può leggere e scrivere ovunque il suo utente di sistema abbia permessi NULL: le operazioni su file sono completamente disabilitate La mia istanza era configurata con un percorso specifico. Il tentativo di scrivere in /tmp/ era stato bloccato perché /tmp/ non è /var/lib/mysql-files/.\nLa prima reazione — quella che vedo fare a molti — sarebbe stata: \u0026ldquo;cambiamo secure-file-priv a stringa vuota nel my.cnf e riavviamo\u0026rdquo;. No. Assolutamente no. Su un server di produzione con quattro istanze MySQL, riavviare un\u0026rsquo;istanza alle 11:30 del mattino per un export CSV non è un\u0026rsquo;opzione. E disabilitare una protezione di sicurezza non è mai la risposta giusta, nemmeno in emergenza.\nL\u0026rsquo;alternativa ovvia era scrivere il file nella directory autorizzata:\nSELECT o.id_ordine, o.data_ordine, c.ragione_sociale, o.importo_totale FROM ordini o JOIN clienti c ON o.id_cliente = c.id_cliente WHERE o.data_ordine \u0026gt;= \u0026#39;2025-07-01\u0026#39; ORDER BY o.data_ordine INTO OUTFILE \u0026#39;/var/lib/mysql-files/export_ordini.csv\u0026#39; FIELDS TERMINATED BY \u0026#39;,\u0026#39; ENCLOSED BY \u0026#39;\u0026#34;\u0026#39; LINES TERMINATED BY \u0026#39;\\n\u0026#39;; Ma c\u0026rsquo;era un altro problema. La directory /var/lib/mysql-files/ era quella dell\u0026rsquo;istanza primaria (porta 3306). L\u0026rsquo;istanza sulla porta 3307 aveva il suo datadir separato in /data/mysql-app2/, e la sua secure_file_priv puntava a /data/mysql-app2/files/ — una directory che non esisteva e che nessuno aveva mai creato.\nAvrei potuto creare la directory, assegnare i permessi corretti all\u0026rsquo;utente mysql e scrivere lì. Ma a quel punto stavo già perdendo tempo. E c\u0026rsquo;è un modo più pulito.\nLa soluzione: export da shell con il client mysql #Quando INTO OUTFILE è bloccato o scomodo, la soluzione più pratica è bypassare completamente il meccanismo di scrittura file di MySQL e usare il client da riga di comando per redirigere l\u0026rsquo;output.\nIl trucco sta nelle opzioni -B (batch mode) e -e (execute):\nmysql --socket=/var/run/mysqld/mysqld-app2.sock \\ -u root -p \\ -B -e \u0026#34; SELECT o.id_ordine, o.data_ordine, c.ragione_sociale, o.importo_totale FROM ordini o JOIN clienti c ON o.id_cliente = c.id_cliente WHERE o.data_ordine \u0026gt;= \u0026#39;2025-07-01\u0026#39; ORDER BY o.data_ordine \u0026#34; gestionale_prod \u0026gt; /tmp/export_ordini.tsv L\u0026rsquo;opzione -B produce un output tab-separated senza i bordi ASCII delle tabelle. Il risultato è un file TSV pulito che si apre senza problemi in qualsiasi foglio di calcolo.\nSe serve un vero CSV con le virgole come separatore, basta un passaggio con sed:\nmysql --socket=/var/run/mysqld/mysqld-app2.sock \\ -u root -p \\ -B -N -e \u0026#34; SELECT o.id_ordine, o.data_ordine, c.ragione_sociale, o.importo_totale FROM ordini o JOIN clienti c ON o.id_cliente = c.id_cliente WHERE o.data_ordine \u0026gt;= \u0026#39;2025-07-01\u0026#39; ORDER BY o.data_ordine \u0026#34; gestionale_prod | sed \u0026#39;s/\\t/,/g\u0026#39; \u0026gt; /tmp/export_ordini.csv L\u0026rsquo;opzione -N rimuove la riga di intestazione con i nomi delle colonne. Se la vuoi, togli il flag.\nIl file era pronto in meno di un minuto. 12.400 righe, 1,2 MB. L\u0026rsquo;ho copiato sulla mia macchina con scp, verificato l\u0026rsquo;apertura in LibreOffice Calc, e inviato al richiedente. Erano le 11:45. Il ticket che doveva durare cinque minuti ne aveva richiesti quarantacinque — ma almeno non avevo riavviato nessuna istanza.\nPerché non disabilitare secure-file-priv #La tentazione di impostare secure_file_priv = \u0026quot;\u0026quot; è forte, soprattutto su server di sviluppo o su macchine dove \u0026ldquo;tanto siamo solo noi\u0026rdquo;. Il problema è che quella protezione esiste per un motivo preciso.\nSenza secure_file_priv, un utente MySQL con il privilegio FILE può:\nLeggere qualsiasi file leggibile dall\u0026rsquo;utente di sistema mysql — inclusi /etc/passwd, file di configurazione, chiavi SSH se i permessi non sono blindati Scrivere file ovunque l\u0026rsquo;utente mysql abbia permessi di scrittura — inclusa la webroot di un eventuale Apache o Nginx sullo stesso server In un contesto di SQL injection , il privilegio FILE combinato con un secure_file_priv vuoto è una porta aperta. L\u0026rsquo;attaccante può leggere file di sistema, scrivere web shell, fare escalation. Non è teoria — è uno dei vettori di attacco più documentati nelle penetration test su applicazioni web con MySQL dietro.\nLa regola è semplice: secure_file_priv si configura con un percorso specifico, si creano le directory necessarie per ogni istanza al momento del setup, e si lasciano lì. Se serve fare export occasionali, il client mysql da shell fa lo stesso lavoro senza toccare la configurazione di sicurezza.\nLezioni da un ticket da cinque minuti #Quel ticket mi ha ricordato tre cose che in trent\u0026rsquo;anni di lavoro con i database ho visto confermate centinaia di volte.\nLa prima: in un ambiente multi-istanza, il primo passo è sempre identificare l\u0026rsquo;istanza. Sembra ovvio, ma la quantità di errori che nascono dal connettersi all\u0026rsquo;istanza sbagliata — pensando di essere altrove — è impressionante. Un SHOW VARIABLES LIKE 'port' dopo ogni connessione non è paranoia, è igiene operativa.\nLa seconda: secure-file-priv non è un ostacolo, è una protezione. Quando ti blocca, non è il momento di disabilitarla. È il momento di usare un percorso alternativo o un metodo alternativo. La direttiva esiste perché MySQL in mano a un utente con il privilegio FILE e nessun vincolo sul filesystem è un rischio concreto.\nLa terza: il client mysql da riga di comando è più potente di quanto la maggior parte dei DBA gli riconosca. Con -B, -N, -e e una pipe verso sed o awk, puoi fare export, trasformazioni e automazioni senza mai toccare INTO OUTFILE. È meno elegante, forse. Ma funziona sempre, non richiede permessi speciali e non ha bisogno che qualcuno abbia creato la directory giusta sei mesi prima.\nIl CSV è arrivato alle 11:45. Il richiedente non ha mai saputo che dietro cinque colonne e 12.400 righe c\u0026rsquo;erano quarantacinque minuti di archeologia sistemistica. Ma è così che funzionano i ticket: chi li apre vede il risultato, chi li risolve vede il percorso.\nGlossario #secure-file-priv — Direttiva di sicurezza MySQL che limita le directory in cui il server può leggere e scrivere file tramite INTO OUTFILE, LOAD DATA INFILE e LOAD_FILE().\nUnix Socket — Meccanismo di comunicazione locale tra processi su sistemi Linux, usato da MySQL come metodo di connessione predefinito quando ci si collega a localhost.\nINTO OUTFILE — Clausola SQL di MySQL per esportare il risultato di una query direttamente in un file sul filesystem del server. Soggetta alle restrizioni di secure-file-priv.\nsystemd — Gestore dei servizi su Linux moderno, usato per gestire istanze multiple di MySQL sullo stesso server tramite unit file separati.\nSQL Injection — Tecnica di attacco che inserisce codice SQL malevolo negli input di un\u0026rsquo;applicazione. La direttiva secure-file-priv contribuisce a mitigarne l\u0026rsquo;impatto.\n","date":"4 novembre 2025","permalink":"https://ivanluminaria.com/it/posts/mysql/mysql-multi-istanza-secure-file-priv/","section":"Database Strategy","summary":"\u003cp\u003eIl ticket diceva: \u0026ldquo;Serve un export CSV dalla tabella ordini del gestionale. Entro le 14.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eErano le 11. Tre ore per una SELECT con INTO OUTFILE — roba da cinque minuti, pensavo. Poi ho aperto la VPN, mi sono collegato al server e ho capito che cinque minuti non sarebbero bastati.\u003c/p\u003e\n\u003cp\u003eIl server era una macchina CentOS 7 con quattro istanze MySQL. Quattro. Sullo stesso host, con quattro servizi \u003cspan class=\"glossary-tip\" tabindex=\"0\" data-glossary-desc=\"Sistema di init e gestore dei servizi su Linux, usato per gestire istanze multiple di MySQL/MariaDB sullo stesso server tramite unit file separati.\" data-glossary-url=\"/it/glossary/systemd/\" data-glossary-more=\"Leggi di più →\"\u003esystemd\u003c/span\u003e\n diversi, quattro porte diverse, quattro socket Unix diverse, quattro directory dati diverse. Un setup che qualcuno aveva messo in piedi anni prima — probabilmente per risparmiare su un secondo server — e che da allora nessuno aveva più toccato né documentato.\u003c/p\u003e","title":"MySQL multi-istanza: un ticket, un CSV e il muro di secure-file-priv"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/secure-file-priv/","section":"Tags","summary":"","title":"Secure-File-Priv"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/socket/","section":"Tags","summary":"","title":"Socket"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/systemd/","section":"Tags","summary":"","title":"Systemd"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/troubleshooting/","section":"Tags","summary":"","title":"Troubleshooting"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/explain/","section":"Tags","summary":"","title":"Explain"},{"content":"L\u0026rsquo;altro giorno un collega mi manda uno screenshot su Teams. Una query che gira su una tabella da 2 milioni di righe, 45 secondi di esecuzione. Mi scrive:\n\u0026ldquo;Ho fatto EXPLAIN ANALYZE, ma non capisco cosa c\u0026rsquo;è che non va. Il piano sembra corretto.\u0026rdquo;\nSpoiler: il piano non era affatto corretto. L\u0026rsquo;optimizer aveva scelto un nested loop join dove serviva un hash join , e la ragione era banale — statistiche non aggiornate. Ma per arrivarci ho dovuto leggere il piano riga per riga, e lì mi sono reso conto che la maggior parte dei DBA che conosco usa EXPLAIN ANALYZE come un oracolo binario: se il tempo è alto, la query è lenta. Fine dell\u0026rsquo;analisi.\nNo. EXPLAIN ANALYZE è uno strumento di diagnostica, non un verdetto. Bisogna saperlo leggere.\n🔧 EXPLAIN, EXPLAIN ANALYZE, EXPLAIN (ANALYZE, BUFFERS): tre cose diverse #Partiamo dalle basi, perché la confusione è più diffusa di quanto si creda.\nEXPLAIN da solo mostra il piano stimato. L\u0026rsquo;optimizer decide cosa farebbe, ma non esegue nulla. Utile per capire la strategia, inutile per capire la realtà.\nEXPLAIN SELECT * FROM orders o JOIN customers c ON c.id = o.customer_id WHERE o.created_at \u0026gt; \u0026#39;2025-01-01\u0026#39;; EXPLAIN ANALYZE esegue la query e aggiunge i tempi reali. Ora vedi quanto ha impiegato ogni nodo, quante righe ha effettivamente restituito. Ma manca un pezzo.\nEXPLAIN ANALYZE SELECT * FROM orders o JOIN customers c ON c.id = o.customer_id WHERE o.created_at \u0026gt; \u0026#39;2025-01-01\u0026#39;; EXPLAIN (ANALYZE, BUFFERS) è quello che uso sempre. Aggiunge le informazioni su quante pagine disco ha letto, quante erano in cache (shared hit) e quante ha dovuto caricare da disco (shared read). Senza BUFFERS stai guidando di notte senza fari.\nEXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders o JOIN customers c ON c.id = o.customer_id WHERE o.created_at \u0026gt; \u0026#39;2025-01-01\u0026#39;; Regola personale: se qualcuno mi manda un EXPLAIN senza BUFFERS, glielo rimando indietro.\n📖 Anatomia di un nodo: cosa leggere e in che ordine #Un piano di esecuzione è un albero. Ogni nodo ha questa struttura:\n-\u0026gt; Hash Join (cost=1234.56..5678.90 rows=50000 width=120) (actual time=12.345..89.012 rows=48750 loops=1) Buffers: shared hit=1200 read=3400 Ecco cosa guardare:\ncost — sono due numeri separati da ... Il primo è il costo di startup (quanto prima di restituire la prima riga), il secondo è il costo totale stimato. Sono unità arbitrarie dell\u0026rsquo;optimizer, non millisecondi. Servono per confrontare piani alternativi, non per misurare performance assolute.\nrows — le righe stimate dall\u0026rsquo;optimizer. Confrontale con actual rows. Se c\u0026rsquo;è un ordine di grandezza di differenza, hai trovato il problema.\nactual time — tempo reale in millisecondi. Anche qui due valori: startup e totale. Attenzione al campo loops: se loops=10, il tempo totale va moltiplicato per 10.\nBuffers — shared hit sono le pagine trovate in memoria, shared read quelle lette da disco. Se read domina, il tuo working set non sta in RAM.\n🚨 Il segnale d\u0026rsquo;allarme numero uno: rows stimate vs rows reali #Torno al caso del mio collega. Il piano mostrava:\n-\u0026gt; Nested Loop (cost=0.87..45678.12 rows=150 width=200) (actual time=0.034..44890.123 rows=1950000 loops=1) L\u0026rsquo;optimizer stimava 150 righe. In realtà ne arrivavano quasi 2 milioni.\nQuando la stima è sbagliata di 4 ordini di grandezza, il piano è inevitabilmente sbagliato. L\u0026rsquo;optimizer ha scelto un nested loop perché pensava di iterare su 150 righe. Un nested loop su 150 righe è velocissimo. Su 2 milioni è un disastro.\nUn hash join o un merge join sarebbero stati la scelta corretta. Ma l\u0026rsquo;optimizer non poteva saperlo con le statistiche che aveva.\nCome regola pratica: se il rapporto tra righe stimate e righe reali supera 10x, hai un problema di statistiche. Sopra 100x, il piano è quasi certamente sbagliato.\n🔍 Perché le statistiche mentono #PostgreSQL mantiene statistiche sulle tabelle in pg_statistic (leggibili tramite pg_stats). Queste statistiche includono:\ndistribuzione dei valori (most common values) istogramma dei valori numero di valori distinti percentuale di NULL L\u0026rsquo;optimizer usa queste informazioni per stimare la selettività di ogni condizione WHERE e la cardinalità di ogni join.\nIl problema? Le statistiche si aggiornano con `ANALYZE` — che può essere manuale o gestito dall\u0026rsquo;autovacuum. Ma l\u0026rsquo;autovacuum lancia ANALYZE solo quando il numero di righe modificate supera una soglia:\nthreshold = autovacuum_analyze_threshold + autovacuum_analyze_scale_factor × n_live_tuples Di default: 50 righe + 10% delle righe vive. Su una tabella da 2 milioni di righe, servono 200.000 modifiche prima che scatti l\u0026rsquo;ANALYZE automatico.\nNel caso del mio collega, la tabella orders era cresciuta da 500.000 a 2 milioni di righe in tre settimane — un import massivo da un sistema legacy. L\u0026rsquo;autovacuum non aveva ancora aggiornato le statistiche perché il 10% di 500.000 (la dimensione nota) era 50.000, e le righe aggiunte erano state inserite in batch che non avevano superato la soglia singolarmente.\nRisultato: l\u0026rsquo;optimizer ragionava ancora come se la tabella avesse 500.000 righe con la vecchia distribuzione dei valori.\n🛠️ Aggiornare le statistiche: la prima cosa da fare #La soluzione immediata era ovvia:\nANALYZE orders; Dopo l\u0026rsquo;ANALYZE, ho rilanciato la query con EXPLAIN (ANALYZE, BUFFERS):\n-\u0026gt; Hash Join (cost=8500.00..32000.00 rows=1940000 width=200) (actual time=120.000..2800.000 rows=1950000 loops=1) Buffers: shared hit=28000 read=4500 Da 45 secondi a meno di 3 secondi. L\u0026rsquo;optimizer aveva scelto un hash join, la stima delle righe era corretta, e il piano era completamente diverso.\nMa non mi sono fermato qui. Se il problema si è presentato una volta, si ripresenterà.\n📊 default_statistics_target: quando 100 non basta #PostgreSQL raccoglie 100 valori di campione per colonna come default. Per tabelle piccole o con distribuzione uniforme, è sufficiente. Per tabelle grandi con distribuzione non uniforme, 100 campioni possono dare una rappresentazione distorta.\nNel caso della tabella orders, la colonna customer_id aveva una distribuzione molto skewed: il 5% dei clienti generava il 60% degli ordini. Con 100 campioni, l\u0026rsquo;optimizer non coglieva questa asimmetria.\nLa soluzione:\nALTER TABLE orders ALTER COLUMN customer_id SET STATISTICS 500; ANALYZE orders; Dopo aver aumentato il target a 500, le stime dell\u0026rsquo;optimizer sulla cardinalità dei join con customers sono diventate molto più accurate.\nRegola: se una colonna è usata frequentemente in WHERE o JOIN e ha distribuzione non uniforme, alza il target. 500 è un buon punto di partenza. Puoi arrivare a 1000, ma oltre raramente porta benefici e rallenta l\u0026rsquo;ANALYZE stesso.\n⚠️ Quando forzare il planner: enable_nestloop e enable_hashjoin #A volte, anche con statistiche aggiornate, l\u0026rsquo;optimizer prende una strada sbagliata. Capita con query complesse, molte tabelle in join, o quando la correlazione tra colonne inganna le stime.\nPostgreSQL offre dei parametri per disabilitare specifiche strategie:\nSET enable_nestloop = off; Questo forza l\u0026rsquo;optimizer a non usare nested loop. Non è una soluzione, è un cerotto diagnostico. Se disabiliti il nested loop e la query passa da 45 secondi a 3 secondi, hai confermato che il problema era la scelta del join. Ma non puoi lasciare enable_nestloop = off in produzione perché ci sono mille query dove il nested loop è la scelta giusta.\nUso questi parametri solo in due scenari:\nDiagnostica: per confermare quale strategia di join è il problema Emergenza: quando il business è fermo e devi far ripartire una query critica mentre cerchi la vera soluzione Dopo la diagnostica, il fix corretto è sempre su statistiche, indici, o riscrittura della query.\n📋 Il mio workflow quando una query è lenta #Dopo trent\u0026rsquo;anni a fare questo mestiere, il mio processo è diventato quasi meccanico:\n1. EXPLAIN (ANALYZE, BUFFERS) — sempre con BUFFERS. Salvo l\u0026rsquo;output completo, non solo le ultime righe.\n2. Cerco la discrepanza rows — confronto rows= stimato con actual rows= reale su ogni nodo. Parto dai nodi foglia e salgo verso la root. La prima discrepanza significativa è quasi sempre la causa.\n3. Controllo le statistiche — guardo pg_stats per le colonne coinvolte. Verifico last_autoanalyze e last_analyze in pg_stat_user_tables. Se l\u0026rsquo;ultimo ANALYZE è vecchio, lo lancio e rivaluto.\n4. Valuto BUFFERS — se shared read è molto alto rispetto a shared hit, il problema potrebbe essere I/O, non il piano. In quel caso il fix è shared_buffers o il working set semplicemente non sta in RAM.\n5. Testo alternative — se le statistiche sono aggiornate ma il piano è ancora sbagliato, uso enable_nestloop, enable_hashjoin, enable_mergejoin per capire quale strategia funziona meglio. Poi cerco di guidare l\u0026rsquo;optimizer verso quella strategia con indici o riscrittura.\nNiente di spettacolare. Nessun trucco magico. Solo lettura sistematica del piano, una riga alla volta.\n💬 La lezione di quel giorno #Il mio collega, dopo aver visto la differenza, mi ha detto: \u0026ldquo;Ma allora bastava un ANALYZE?\u0026rdquo;\nSì e no. In quel caso specifico, sì. Ma il punto non è il comando. Il punto è saper leggere il piano per capire dove guardare. EXPLAIN ANALYZE ti dà i dati. Sta a te interpretarli.\nHo visto DBA con anni di esperienza lanciare EXPLAIN ANALYZE, guardare il tempo totale in fondo, e dire \u0026ldquo;la query è lenta\u0026rdquo;. È come guardare la temperatura di un paziente e dire \u0026ldquo;ha la febbre\u0026rdquo;. Sì, ma da cosa dipende?\nIl piano di esecuzione ti dice da cosa dipende. Ogni nodo è un organo. Le righe stimate contro quelle reali sono i valori di laboratorio. I buffer sono le lastre. E l\u0026rsquo;ANALYZE è l\u0026rsquo;antibiotico che risolve il 70% dei casi.\nMa per quel restante 30%, devi leggere. Riga per riga. Nodo per nodo. Non c\u0026rsquo;è scorciatoia.\nGlossario #Execution Plan — la sequenza di operazioni (scan, join, sort) che il database sceglie per risolvere una query SQL. Si visualizza con EXPLAIN e EXPLAIN ANALYZE.\nNested Loop — strategia di join che per ogni riga della tabella esterna cerca le corrispondenze nella tabella interna. Ideale per poche righe, disastrosa su grandi volumi quando scelta per errore dall\u0026rsquo;optimizer.\nHash Join — strategia di join che costruisce una hash table dalla tabella più piccola e poi scansiona la più grande cercando corrispondenze con lookup O(1). Efficiente su grandi volumi senza indici.\nANALYZE — comando PostgreSQL che raccoglie statistiche sulla distribuzione dei dati nelle tabelle, usate dall\u0026rsquo;optimizer per stimare la cardinalità e scegliere il piano di esecuzione.\ndefault_statistics_target — parametro PostgreSQL che definisce quanti campioni raccogliere per colonna durante l\u0026rsquo;ANALYZE. Il default è 100; su colonne con distribuzione asimmetrica conviene alzarlo a 500-1000.\n","date":"28 ottobre 2025","permalink":"https://ivanluminaria.com/it/posts/postgresql/explain-analyze-postgresql/","section":"Database Strategy","summary":"\u003cp\u003eL\u0026rsquo;altro giorno un collega mi manda uno screenshot su Teams. Una query che gira su una tabella da 2 milioni di righe, 45 secondi di esecuzione. Mi scrive:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u0026ldquo;Ho fatto EXPLAIN ANALYZE, ma non capisco cosa c\u0026rsquo;è che non va. Il piano sembra corretto.\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eSpoiler: il piano non era affatto corretto. L\u0026rsquo;optimizer aveva scelto un \u003cspan class=\"glossary-tip\" tabindex=\"0\" data-glossary-desc=\"Nested Loop Join — strategia di join che scansiona la tabella interna per ogni riga della tabella esterna, ideale per dataset piccoli con indice.\" data-glossary-url=\"/it/glossary/nested-loop/\" data-glossary-more=\"Leggi di più →\"\u003enested loop\u003c/span\u003e\n join dove serviva un \u003cspan class=\"glossary-tip\" tabindex=\"0\" data-glossary-desc=\"Hash Join — strategia di join ottimizzata per grandi volumi di dati, basata su una hash table costruita in memoria.\" data-glossary-url=\"/it/glossary/hash-join/\" data-glossary-more=\"Leggi di più →\"\u003ehash join\u003c/span\u003e\n, e la ragione era banale — statistiche non aggiornate. Ma per arrivarci ho dovuto leggere il piano riga per riga, e lì mi sono reso conto che la maggior parte dei DBA che conosco usa EXPLAIN ANALYZE come un oracolo binario: se il tempo è alto, la query è lenta. Fine dell\u0026rsquo;analisi.\u003c/p\u003e","title":"EXPLAIN ANALYZE non basta: come leggere davvero un piano di esecuzione PostgreSQL"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/optimizer/","section":"Tags","summary":"","title":"Optimizer"},{"content":"La riunione era cominciata bene. Il direttore commerciale di un\u0026rsquo;azienda di distribuzione industriale — una sessantina di milioni di fatturato, tremila clienti attivi, catalogo con dodicimila referenze — aveva aperto la presentazione del nuovo data warehouse con un sorriso. I numeri tornavano, i cruscotti erano belli, i totali mensili per agente e per zona battevano con la contabilità.\nPoi qualcuno ha fatto la domanda sbagliata. O meglio, quella giusta.\n\u0026ldquo;Posso vedere quanto ha comprato il cliente Bianchi nel mese di marzo, riga per riga, prodotto per prodotto?\u0026rdquo;\nSilenzio.\nIl responsabile BI ha guardato me. Io ho guardato lo schermo. Lo schermo mostrava una fact table con una riga per cliente per mese: importo totale fatturato, quantità totale, numero fatture. Nessun dettaglio. Nessuna riga di fattura. Nessun prodotto.\nQuella fact table rispondeva a una sola domanda: quanto ha fatturato ciascun cliente in un dato mese? Tutto il resto — per prodotto, per famiglia merceologica, per singola fattura — era fuori portata.\n🔍 Il grain: la decisione che determina tutto #Nel dimensional modeling , il grain (la grana) della fact table è la prima decisione da prendere. Non la seconda, non una tra tante: la prima. Kimball lo ripete in ogni capitolo, e ha ragione.\nIl grain risponde alla domanda: cosa rappresenta una singola riga della fact table?\nNel progetto che ho descritto, chi aveva progettato il modello aveva scelto un grain mensile-cliente: una riga = un cliente in un mese. I motivi sembravano ragionevoli: il sistema sorgente esportava un riepilogo mensile, il caricamento era veloce, le tabelle erano piccole, le query semplici.\nMa il grain determina le domande a cui il data warehouse può rispondere. Se la grana è il riepilogo mensile per cliente, non puoi scendere sotto quel livello. Non puoi fare drill-down per prodotto. Non puoi sapere se il cliente Bianchi ha comprato dieci volte lo stesso articolo o dieci articoli diversi. Non puoi confrontare margini per famiglia merceologica.\nHai un totale. Punto.\n📊 I numeri del problema #La fact table originale aveva questa struttura:\nCREATE TABLE fact_fatturato_mensile ( sk_cliente INT NOT NULL, sk_tempo INT NOT NULL, -- mese (YYYYMM) sk_agente INT NOT NULL, sk_zona INT NOT NULL, importo_totale DECIMAL(15,2), quantita_totale INT, num_fatture INT, num_righe INT, FOREIGN KEY (sk_cliente) REFERENCES dim_cliente(sk_cliente), FOREIGN KEY (sk_tempo) REFERENCES dim_tempo(sk_tempo) ); Righe in tabella: circa 180.000 all\u0026rsquo;anno (3.000 clienti × 12 mesi × qualche variazione). Piccola, veloce, facile da caricare. L\u0026rsquo;ETL girava in meno di cinque minuti.\nIl problema? Le misure additive erano già aggregate. importo_totale era la somma di tutte le righe di fattura del mese. Impossibile risalire alla composizione. Come avere il totale di uno scontrino senza sapere cosa hai comprato.\n🏗️ La ristrutturazione: scendere alla riga di fattura #La soluzione era una sola: cambiare il grain. Portare la fact table al livello più basso disponibile nel sistema sorgente — la singola riga di fattura.\nCREATE TABLE fact_fatturato_riga ( sk_riga_fattura INT PRIMARY KEY, sk_fattura INT NOT NULL, sk_cliente INT NOT NULL, sk_prodotto INT NOT NULL, sk_tempo INT NOT NULL, -- giorno (YYYYMMDD) sk_agente INT NOT NULL, sk_zona INT NOT NULL, sk_famiglia INT NOT NULL, quantita INT, prezzo_unitario DECIMAL(12,4), importo_riga DECIMAL(15,2), sconto_perc DECIMAL(5,2), importo_netto DECIMAL(15,2), costo_prodotto DECIMAL(15,2), margine DECIMAL(15,2), FOREIGN KEY (sk_cliente) REFERENCES dim_cliente(sk_cliente), FOREIGN KEY (sk_prodotto) REFERENCES dim_prodotto(sk_prodotto), FOREIGN KEY (sk_tempo) REFERENCES dim_tempo(sk_tempo) ); Righe in tabella: circa 2,4 milioni all\u0026rsquo;anno (3.000 clienti × ~800 righe/anno in media). Un ordine di grandezza in più. Ma ogni riga porta con sé il dettaglio completo: quale prodotto, quale fattura, quale prezzo, quale sconto, quale margine.\n⚡ L\u0026rsquo;impatto sull\u0026rsquo;ETL #Il cambiamento di grain ha avuto un effetto a cascata sull\u0026rsquo;ETL che nessuno aveva previsto — o meglio, che chi aveva scelto il grain aggregato aveva evitato di affrontare.\nNuove dimensioni necessarie:\nDimensione Cardinalità Note dim_prodotto ~12.000 Non esisteva: prima non serviva dim_famiglia ~180 Gerarchia merceologica a 3 livelli dim_fattura ~45.000/anno Header fattura con dati di testata Nuova finestra di caricamento:\nFase Prima Dopo Estrazione 40 sec 3 min Trasformazione 1 min 8 min Caricamento fact 30 sec 4 min Totale ~2 min ~15 min Quindici minuti contro due. Un prezzo accettabile per un data warehouse che adesso rispondeva a domande reali.\n🔬 Le domande che prima erano impossibili #Con il nuovo grain, le query che il business voleva diventavano banali:\nDettaglio acquisti di un cliente per prodotto:\nSELECT c.ragione_sociale, p.codice_prodotto, p.descrizione, SUM(f.quantita) AS pezzi, SUM(f.importo_netto) AS fatturato_netto, SUM(f.margine) AS margine_totale FROM fact_fatturato_riga f JOIN dim_cliente c ON f.sk_cliente = c.sk_cliente JOIN dim_prodotto p ON f.sk_prodotto = p.sk_prodotto JOIN dim_tempo t ON f.sk_tempo = t.sk_tempo WHERE c.ragione_sociale = \u0026#39;Bianchi Srl\u0026#39; AND t.anno = 2024 AND t.mese = 3 GROUP BY c.ragione_sociale, p.codice_prodotto, p.descrizione ORDER BY fatturato_netto DESC; Top 10 prodotti per marginalità in un trimestre:\nSELECT p.codice_prodotto, p.descrizione, fm.desc_famiglia, SUM(f.importo_netto) AS fatturato, SUM(f.margine) AS margine, ROUND(SUM(f.margine) / NULLIF(SUM(f.importo_netto), 0) * 100, 1) AS margine_perc FROM fact_fatturato_riga f JOIN dim_prodotto p ON f.sk_prodotto = p.sk_prodotto JOIN dim_famiglia fm ON f.sk_famiglia = fm.sk_famiglia JOIN dim_tempo t ON f.sk_tempo = t.sk_tempo WHERE t.anno = 2024 AND t.trimestre = 1 GROUP BY p.codice_prodotto, p.descrizione, fm.desc_famiglia ORDER BY margine DESC LIMIT 10; Confronto agente: fatturato medio per riga di fattura:\nSELECT a.nome_agente, COUNT(*) AS num_righe, SUM(f.importo_netto) AS fatturato_totale, ROUND(AVG(f.importo_netto), 2) AS media_per_riga FROM fact_fatturato_riga f JOIN dim_agente a ON f.sk_agente = a.sk_agente JOIN dim_tempo t ON f.sk_tempo = t.sk_tempo WHERE t.anno = 2024 GROUP BY a.nome_agente ORDER BY fatturato_totale DESC; Nessuna di queste query era possibile con il grain mensile-cliente. Zero. Non era un problema di ottimizzazione o di indici — era un problema strutturale, scritto nel DNA del modello.\n📋 La regola di Kimball che avevamo ignorato #Ralph Kimball lo dice in modo chiaro: \u0026ldquo;sempre modellare al livello di dettaglio più fine disponibile nel sistema sorgente\u0026rdquo;.\nNon è un suggerimento. Non è un\u0026rsquo;opzione tra tante. È il principio fondante del dimensional modeling. E il motivo è semplice: si può sempre aggregare dal dettaglio al totale, ma non si può mai disaggregare un totale nel suo dettaglio.\nL\u0026rsquo;aggregazione è un\u0026rsquo;operazione irreversibile. Come mescolare i colori: dal rosso e dal giallo puoi ottenere l\u0026rsquo;arancione, ma dall\u0026rsquo;arancione non torni più ai colori originali.\nNel caso del nostro progetto, la scelta del grain aggregato era stata dettata dalla pigrizia progettuale, non da un vincolo tecnico. Il sistema sorgente aveva il dettaglio per riga di fattura — semplicemente nessuno aveva voluto affrontare la complessità di modellarlo, gestire le dimensioni aggiuntive, allungare i tempi dell\u0026rsquo;ETL.\nIl risultato? Un data warehouse che andava ricostruito da zero dopo sei mesi dal go-live.\n🎯 Quando il grain aggregato ha senso #Non sempre la grana fine è l\u0026rsquo;unica risposta. Ci sono casi legittimi per le fact table aggregate:\nTabelle di aggregazione (aggregate fact table) affiancate alla tabella di dettaglio, per velocizzare le query più frequenti Snapshot periodici dove il business ragiona effettivamente per periodo (saldo mensile di un conto corrente, giacenza di magazzino a fine settimana) Vincoli di sorgente quando il sistema a monte non espone il dettaglio e non c\u0026rsquo;è modo di ottenerlo Ma la regola è: parti dal dettaglio, poi aggrega. Mai il contrario. Le aggregate fact table sono un\u0026rsquo;ottimizzazione, non un sostituto della grana fine.\nNel nostro caso, dopo la ristrutturazione, abbiamo creato anche una vista materializzata con il riepilogo mensile per cliente — la stessa struttura di prima — per i cruscotti direzionali che non avevano bisogno del dettaglio. Il meglio dei due mondi, senza sacrificare nulla.\nQuello che ho imparato #Quel progetto mi ha insegnato una cosa che porto con me in ogni incarico successivo: la prima mezz\u0026rsquo;ora di progettazione di un data warehouse, quella in cui si decide il grain, vale più di tutte le ottimizzazioni che verranno dopo. Un ETL perfetto, indici calibrati, hardware potente — niente di tutto questo compensa un grain sbagliato.\nSe la tua fact table non risponde alle domande del business, non è colpa delle query. È colpa del modello. E il modello si decide al grain.\nGlossario #Grain — Il livello di dettaglio (grana) di una fact table nel data warehouse. Determina cosa rappresenta ciascuna riga e quali domande il modello può soddisfare. È la prima decisione da prendere nella progettazione dimensionale.\nFact table — Tabella centrale dello star schema che contiene le misure numeriche (importi, quantità, margini) e le chiavi esterne verso le dimensioni. La sua grana determina il livello di analisi possibile.\nAdditive Measure — Misura numerica che può essere sommata lungo tutte le dimensioni (es. importo, quantità). Una volta aggregata a livello superiore, il dettaglio originale è perso irreversibilmente.\nDrill-down — Navigazione nei report dal livello aggregato al dettaglio, lungo una gerarchia. Possibile solo se la fact table contiene dati al livello di grana sufficiente.\nStar Schema — Modello di dati con una fact table al centro e tabelle dimensionali collegate. La struttura più usata nei data warehouse per la semplicità delle query analitiche.\nETL — Extract, Transform, Load: il processo di estrazione, trasformazione e caricamento dei dati nel data warehouse. Un cambio di grain impatta direttamente tempi e complessità dell\u0026rsquo;ETL.\n","date":"21 ottobre 2025","permalink":"https://ivanluminaria.com/it/posts/data-warehouse/fatto-grana-sbagliata/","section":"Database Strategy","summary":"\u003cp\u003eLa riunione era cominciata bene. Il direttore commerciale di un\u0026rsquo;azienda di distribuzione industriale — una sessantina di milioni di fatturato, tremila clienti attivi, catalogo con dodicimila referenze — aveva aperto la presentazione del nuovo data warehouse con un sorriso. I numeri tornavano, i cruscotti erano belli, i totali mensili per agente e per zona battevano con la contabilità.\u003c/p\u003e\n\u003cp\u003ePoi qualcuno ha fatto la domanda sbagliata. O meglio, quella giusta.\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e\u0026ldquo;Posso vedere quanto ha comprato il cliente Bianchi nel mese di marzo, riga per riga, prodotto per prodotto?\u0026rdquo;\u003c/em\u003e\u003c/p\u003e","title":"Fatto a grana sbagliata: quando la fact table non risponde alle domande giuste"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/grain/","section":"Tags","summary":"","title":"Grain"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/granularity/","section":"Tags","summary":"","title":"Granularity"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/binary-log/","section":"Tags","summary":"","title":"Binary-Log"},{"content":"La notifica è arrivata un lunedì mattina, in mezzo a tre riunioni e un caffè ancora caldo. \u0026ldquo;Filesystem /mysql all'85% sul nodo primario.\u0026rdquo; Su un altro nodo era al 66%, sul terzo al 25%. In un cluster, quando i numeri non tornano tra i nodi, c\u0026rsquo;è sempre qualcosa sotto.\nLa prima domanda che ti viene in mente è \u0026ldquo;quanto spazio serve?\u0026rdquo;. Ma è la domanda sbagliata. Quella giusta è: \u0026ldquo;perché si sta riempiendo?\u0026rdquo;\nLa causa: binary log sul volume sbagliato #Controllare è stato rapido:\nSHOW VARIABLES LIKE \u0026#39;log_bin\u0026#39;; Risultato: ON. I binary log erano attivi — come ci si aspetta in un cluster. Ma la cosa che non andava era il path:\nSHOW VARIABLES LIKE \u0026#39;log_bin_basename\u0026#39;; /mysql/bin_log/binlog I binlog stavano sullo stesso volume dei dati: /mysql. Un volume da circa 3 TB che su un nodo era già all'85%.\nHo verificato anche la retention:\nSHOW VARIABLES LIKE \u0026#39;binlog_expire_logs_seconds\u0026#39;; 2592000 Trenta giorni. Poi ho voluto capire quanto pesava davvero questa configurazione. Ho controllato la dimensione dei singoli file binlog e il ritmo di scrittura: ogni file pesava circa 1 GB, e il server ne generava uno ogni due ore. Dodici file al giorno, per trenta giorni di retention: circa 360 GB di binary log sul volume principale. Su un volume da 3 TB condiviso con i dati, i binlog da soli occupavano più del 10% dello spazio. E quei file non stanno solo sul primary — in Group Replication ogni nodo scrive i propri binlog locali per la sincronizzazione, quindi il problema si moltiplicava su tutti e tre i nodi.\nIl problema era chiaro: i binary log stavano mangiando lo spazio del filesystem principale. Non un bug, non una tabella che cresce a dismisura. Solo una scelta architetturale iniziale mai rivista.\nMa che cluster è, esattamente? #Prima di toccare qualsiasi cosa su un server MySQL — prima ancora di pensare a spostare un file — devi sapere cosa hai davanti. \u0026ldquo;È un cluster\u0026rdquo; non basta. MySQL ha almeno quattro modi diversi di fare alta disponibilità, e ognuno ha le sue regole.\nHo iniziato con la replica classica:\nSHOW SLAVE STATUS\\G Empty set su entrambi i nodi che ho controllato. Nessuna replica tradizionale attiva.\nPoi ho provato con SHOW REPLICA STATUS — ma su MySQL 8.0.20 quel comando non esiste ancora. È stato introdotto nella 8.0.22. Un dettaglio che la documentazione online spesso dimentica di specificare, e che ti fa perdere cinque minuti a cercare un errore di sintassi che non è un errore.\nPassaggio successivo — Group Replication:\nSELECT MEMBER_HOST, MEMBER_STATE, MEMBER_ROLE FROM performance_schema.replication_group_members; Ed ecco la risposta:\nMEMBER_HOST MEMBER_STATE MEMBER_ROLE dbcluster01 ONLINE SECONDARY dbcluster02 ONLINE SECONDARY dbcluster03 ONLINE PRIMARY Tre nodi. Tutti ONLINE. Un primary, due secondary. Group Replication in modalità single-primary.\nConferma finale dai plugin:\nSHOW PLUGINS; In mezzo alla lista: group_replication | ACTIVE | GROUP REPLICATION | group_replication.so. E dalla configurazione:\nSHOW VARIABLES LIKE \u0026#39;group_replication_single_primary_mode\u0026#39;; ON Ora sapevo cosa avevo davanti. Non una replica classica, non un Galera, non un cluster NDB. Un MySQL Group Replication single-primary con tre nodi, GTID abilitati, binlog in formato ROW. Il quadro era completo.\nLa tentazione è sempre quella di saltare questa fase. \u0026ldquo;Tanto so che è un cluster, muoviamoci.\u0026rdquo; Ma saltare la diagnosi su un cluster è come operare senza la TAC: puoi avere fortuna, o puoi fare un disastro.\nLa soluzione: un volume dedicato per i binary log #La strategia era semplice: i binlog devono stare su un volume separato. Non sullo stesso filesystem dei dati, non su un symlink improvvisato, non su una directory condivisa. Un volume dedicato, montato nello stesso path su tutti e tre i nodi.\nHo chiesto ai sistemisti di creare un nuovo volume da 600 GB con mount point /mysql/binary_logs su ciascuno dei tre nodi.\nQuando il volume è stato pronto, ho verificato su tutti e tre:\ndf -h /mysql/binary_logs Nodo /mysql /mysql/binary_logs dbcluster03 (PRIMARY) 85% 1% dbcluster02 (SECONDARY) 66% 1% dbcluster01 (SECONDARY) 25% 1% Spazio fresco e dedicato. Ogni volume su un disco locale della VM di competenza — tre dischi, tre volumi, stesso mountpoint per tutti e tre i nodi. I sistemisti avevano fatto un lavoro pulito.\nI check prima di toccare MySQL #Prima di fermare il primo nodo, ho fatto tre controlli che considero obbligatori.\nPermessi sulla directory. MySQL non parte se non può scrivere nella directory dei binlog. Sembra banale, ma è una delle cause più frequenti di \u0026ldquo;perché non riparte dopo il cambio config\u0026rdquo;.\nls -ld /mysql/binary_logs Sui tre nodi i permessi erano 755. Funziona, ma non è il massimo lato sicurezza — i binlog possono contenere dati sensibili. Li ho portati a 750:\nchmod 750 /mysql/binary_logs Risultato: drwxr-x--- mysql mysql. Solo l\u0026rsquo;utente mysql può scrivere e leggere.\nTest di scrittura reale. Prima di far scrivere MySQL, ho verificato che il filesystem rispondesse:\ntouch /mysql/binary_logs/testfile ls -l /mysql/binary_logs/testfile rm -f /mysql/binary_logs/testfile Se il touch fallisce, il problema è dello storage o dei permessi — e meglio scoprirlo adesso che dopo un restart di MySQL.\nStato del cluster. L\u0026rsquo;ultimo controllo prima di procedere:\nSELECT MEMBER_HOST, MEMBER_STATE, MEMBER_ROLE FROM performance_schema.replication_group_members; Tre nodi ONLINE. Quorum intatto. Si può partire.\nLa strategia: un nodo alla volta, il primary per ultimo #In un Group Replication a tre nodi, il quorum è due. Se fermi un nodo, gli altri due mantengono il gruppo. Se ne fermi due — hai perso il cluster.\nLa regola è semplice: un nodo alla volta, aspettando che il precedente rientri nel gruppo prima di toccare il successivo. E il primary si fa per ultimo.\nPerché? Perché quando fermi il primary, succede una cosa importante: il cluster fa un\u0026rsquo;elezione automatica e uno dei secondary diventa il nuovo primary. Durante quei secondi — pochi, se tutto è sano — le connessioni attive possono essere droppate, le transazioni in corso possono fallire. È un disservizio breve, ma è un disservizio. Va comunicato.\nL\u0026rsquo;ordine che ho seguito:\ndbcluster01 (SECONDARY) dbcluster02 (SECONDARY) dbcluster03 (PRIMARY) La procedura, nodo per nodo #Su ogni nodo la sequenza è identica:\nA. Verifica il ruolo del nodo. Prima di fermarlo, conferma che sia quello che pensi:\nSELECT MEMBER_HOST, MEMBER_STATE, MEMBER_ROLE FROM performance_schema.replication_group_members; B. Ferma MySQL:\nsystemctl stop mysqld C. Modifica la configurazione. Nel my.cnf, cambia il parametro log_bin:\nDa:\nlog_bin=/mysql/bin_log/binlog A:\nlog_bin=/mysql/binary_logs/mysql-bin Una riga. Una sola modifica. Non toccare i parametri di Group Replication, non cambiare il server_id, non reinventare il motore a vapore mentre cambi una ruota.\nD. Avvia MySQL:\nsystemctl start mysqld E. Verifica. Tre cose da controllare:\nIl nuovo path:\nSHOW VARIABLES LIKE \u0026#39;log_bin_basename\u0026#39;; Deve restituire /mysql/binary_logs/mysql-bin.\nIl rientro nel gruppo:\nSELECT MEMBER_HOST, MEMBER_STATE, MEMBER_ROLE FROM performance_schema.replication_group_members; Il nodo deve tornare ONLINE.\nI nuovi binlog sul nuovo path:\nls -lh /mysql/binary_logs/ Devono comparire i nuovi file mysql-bin.000001.\nSolo quando il nodo è ONLINE e il cluster mostra di nuovo tre nodi attivi, si passa al successivo. Non prima.\nPer il primary — dbcluster03 — la procedura è identica, ma prima di fermarlo ho verificato che entrambi i secondary fossero ONLINE e già migrati. Al momento dello stop, il cluster ha fatto l\u0026rsquo;elezione. Uno dei secondary è diventato primary. Breve disservizio, come previsto.\nCosa non fare #Dalla mia esperienza, queste sono le trappole più comuni in questo tipo di intervento:\nNon copiare i vecchi binlog nel nuovo path. In Group Replication non serve fare archeologia binaria. I nuovi binlog verranno creati nella nuova directory dopo il riavvio. Quelli vecchi servono solo se hai bisogno di point-in-time recovery — e in quel caso li sai già dove trovarli.\nNon toccare due nodi contemporaneamente. Con tre nodi il quorum è sacro. Un nodo per volta, senza eccezioni. Se fermi due nodi insieme, stai giocando a Jenga bendato.\nNon partire dal primary. Sempre i secondary prima, il primary per ultimo. Fare il contrario è il modo elegante di invitare il caos a cena.\nNon cancellare subito i vecchi binlog. Dopo il cambio, il vecchio path /mysql/bin_log/ non verrà più usato per i nuovi file. Ma non fare subito rm -rf /mysql/bin_log/*. Aspetta. Verifica che il cluster sia stabile, che i nuovi binlog vengano scritti sul nuovo mount, che non ci siano errori nel log di MySQL. Solo dopo qualche giorno di osservazione, ragiona sulla pulizia.\nNon fidarti solo del fatto che \u0026ldquo;MySQL è partito\u0026rdquo;. MySQL può partire ma non rientrare nel gruppo. Devi verificare tre cose: il log_bin_basename punta al nuovo path, il nodo è ONLINE nella tabella replication_group_members, e i file binlog vengono effettivamente scritti nella nuova directory.\nQuello che questa operazione insegna #Un filesystem al 92% non è un\u0026rsquo;emergenza — è un segnale. Il problema vero non era lo spazio disco, era una scelta architetturale fatta probabilmente al momento dell\u0026rsquo;installazione e mai più rivista: binlog e dati sullo stesso volume.\nSeparare i binary log su un volume dedicato non è solo un fix. È hardening dell\u0026rsquo;infrastruttura. È la differenza tra un sistema che \u0026ldquo;funziona\u0026rdquo; e un sistema che è progettato per funzionare anche quando le cose crescono.\nE la parte più importante di tutto l\u0026rsquo;intervento non è stata la modifica del my.cnf — quella è una riga. La parte importante è stata la diagnosi: capire che tipo di cluster avevo davanti, verificare lo stato di ogni nodo, preparare lo storage, testare i permessi, pianificare l\u0026rsquo;ordine di esecuzione. Tutto prima di toccare un solo parametro.\nUn DBA senior e un DBA junior conoscono entrambi il comando systemctl stop mysqld. La differenza è in tutto quello che succede prima.\nGlossario #Group Replication — Meccanismo nativo di MySQL per la replica sincrona multi-nodo con failover automatico e gestione del quorum. Supporta modalità single-primary e multi-primary.\nBinary log — Registro binario sequenziale di MySQL che traccia tutte le modifiche ai dati (INSERT, UPDATE, DELETE, DDL), usato per la replica e il point-in-time recovery.\nGTID — Global Transaction Identifier — identificativo univoco assegnato a ogni transazione in MySQL, che semplifica la gestione della replica e il tracking delle transazioni tra i nodi del cluster.\nQuorum — Numero minimo di nodi che devono essere attivi e in comunicazione perché un cluster possa continuare a operare. In un cluster a 3 nodi, il quorum è 2.\nSingle-primary — Modalità di Group Replication in cui un solo nodo accetta scritture, mentre gli altri sono in sola lettura con failover automatico.\n","date":"14 ottobre 2025","permalink":"https://ivanluminaria.com/it/posts/mysql/mysql-group-replication-binlog-migration/","section":"Database Strategy","summary":"\u003cp\u003eLa notifica è arrivata un lunedì mattina, in mezzo a tre riunioni e un caffè ancora caldo. \u0026ldquo;Filesystem /mysql all'85% sul nodo primario.\u0026rdquo; Su un altro nodo era al 66%, sul terzo al 25%. In un cluster, quando i numeri non tornano tra i nodi, c\u0026rsquo;è sempre qualcosa sotto.\u003c/p\u003e\n\u003cp\u003eLa prima domanda che ti viene in mente è \u0026ldquo;quanto spazio serve?\u0026rdquo;. Ma è la domanda sbagliata. Quella giusta è: \u0026ldquo;perché si sta riempiendo?\u0026rdquo;\u003c/p\u003e","title":"Disco pieno su un cluster MySQL: binary log, Group Replication e la migrazione che non ammette errori"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/group-replication/","section":"Tags","summary":"","title":"Group-Replication"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/tags/innodb-cluster/","section":"Tags","summary":"","title":"Innodb-Cluster"},{"content":"Una additive measure (misura additiva) è un valore numerico in una fact table che può essere legittimamente sommato lungo qualsiasi dimensione: per cliente, per prodotto, per periodo, per zona.\nCome funziona #Le misure nelle fact table si classificano in tre categorie:\nAdditive: possono essere sommate lungo tutte le dimensioni (es. importo vendita, quantità, costo). Sono le più comuni e le più utili Semi-additive: possono essere sommate lungo alcune dimensioni ma non lungo il tempo (es. saldo di un conto: sommabile per filiale, non per mese) Non-additive: non possono essere sommate in alcun modo (es. percentuali, rapporti, medie precalcolate) A cosa serve #Le misure additive sono il cuore di ogni fact table perché permettono le aggregazioni che il business richiede: totali per periodo, per regione, per prodotto. La regola chiave: memorizzare sempre i valori atomici (il dettaglio), mai gli aggregati. Da un importo per riga di fattura puoi ottenere il totale mensile; dal totale mensile non puoi ricostruire le singole righe.\nQuando si usa #Nella progettazione della fact table, ogni misura va classificata come additiva, semi-additiva o non-additiva. Questo determina quali aggregazioni sono lecite nei report e quali produrrebbero risultati errati. Un errore comune è trattare una misura semi-additiva (come un saldo) come se fosse additiva — sommando saldi mensili per ottenere un \u0026ldquo;totale\u0026rdquo; che non ha significato di business.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/additive-measure/","section":"Glossario","summary":"\u003cp\u003eUna \u003cstrong\u003eadditive measure\u003c/strong\u003e (misura additiva) è un valore numerico in una fact table che può essere legittimamente sommato lungo qualsiasi dimensione: per cliente, per prodotto, per periodo, per zona.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLe misure nelle fact table si classificano in tre categorie:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eAdditive\u003c/strong\u003e: possono essere sommate lungo tutte le dimensioni (es. importo vendita, quantità, costo). Sono le più comuni e le più utili\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSemi-additive\u003c/strong\u003e: possono essere sommate lungo alcune dimensioni ma non lungo il tempo (es. saldo di un conto: sommabile per filiale, non per mese)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eNon-additive\u003c/strong\u003e: non possono essere sommate in alcun modo (es. percentuali, rapporti, medie precalcolate)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"a-cosa-serve\" class=\"relative group\"\u003eA cosa serve \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#a-cosa-serve\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLe misure additive sono il cuore di ogni fact table perché permettono le aggregazioni che il business richiede: totali per periodo, per regione, per prodotto. La regola chiave: memorizzare sempre i valori atomici (il dettaglio), mai gli aggregati. Da un importo per riga di fattura puoi ottenere il totale mensile; dal totale mensile non puoi ricostruire le singole righe.\u003c/p\u003e","title":"Additive Measure"},{"content":"L\u0026rsquo;AI Manager è il ruolo professionale che governa l\u0026rsquo;introduzione e l\u0026rsquo;utilizzo dell\u0026rsquo;intelligenza artificiale all\u0026rsquo;interno di un progetto o un\u0026rsquo;organizzazione. Non è chi usa l\u0026rsquo;AI — è chi decide dove, come e con quali precauzioni integrarla nelle architetture esistenti.\nCome funziona #L\u0026rsquo;AI Manager risponde a domande che nessun modello può rispondere: dove l\u0026rsquo;AI genera valore reale e dove genera solo entusiasmo? Quanto costa mantenerla, non solo implementarla? Cosa succede quando il modello sbaglia? Come si integra con le architetture mission-critical senza comprometterne la stabilità?\nA cosa serve #Separa il segnale dal rumore. In un mercato dove ogni vendor promette ROI a tre cifre, l\u0026rsquo;AI Manager identifica i tre ambiti dove l\u0026rsquo;AI genera valore concreto: accelerazione dell\u0026rsquo;analisi, riduzione del rumore decisionale e knowledge transfer automatizzato. Tutto il resto è demo che luccica.\nPerché è critico #Senza qualcuno che governi l\u0026rsquo;AI, le organizzazioni la subiscono. L\u0026rsquo;AI viene integrata senza verificare la provenienza dei dati di training, senza piano di fallback, senza governance. In ambiti regolamentati (banking, PA, sanità) questo è un rischio che può costare molto più dell\u0026rsquo;AI stessa.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/ai-manager/","section":"Glossario","summary":"\u003cp\u003eL\u0026rsquo;\u003cstrong\u003eAI Manager\u003c/strong\u003e è il ruolo professionale che governa l\u0026rsquo;introduzione e l\u0026rsquo;utilizzo dell\u0026rsquo;intelligenza artificiale all\u0026rsquo;interno di un progetto o un\u0026rsquo;organizzazione. Non è chi usa l\u0026rsquo;AI — è chi decide dove, come e con quali precauzioni integrarla nelle architetture esistenti.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eL\u0026rsquo;AI Manager risponde a domande che nessun modello può rispondere: dove l\u0026rsquo;AI genera valore reale e dove genera solo entusiasmo? Quanto costa mantenerla, non solo implementarla? Cosa succede quando il modello sbaglia? Come si integra con le architetture mission-critical senza comprometterne la stabilità?\u003c/p\u003e","title":"AI Manager"},{"content":"ANALYZE è il comando PostgreSQL che raccoglie statistiche sulla distribuzione dei dati nelle tabelle e le salva nel catalogo pg_statistic (leggibile tramite la vista pg_stats). L\u0026rsquo;optimizer usa queste statistiche per stimare la cardinalità — quante righe restituirà ogni operazione — e scegliere il piano di esecuzione più efficiente.\nCosa raccoglie #Le statistiche raccolte da ANALYZE includono:\nMost common values: i valori più frequenti per ogni colonna e la loro percentuale Istogrammi di distribuzione: come sono distribuiti i valori rimanenti Numero di valori distinti: quanti valori unici ha ogni colonna Percentuale di NULL: quante righe hanno valore NULL per ogni colonna La qualità di queste statistiche dipende dal numero di campioni raccolti, controllato dal parametro default_statistics_target.\nPerché è critico #Senza statistiche aggiornate, l\u0026rsquo;optimizer è costretto a indovinare. Le stime sbagliate portano a piani di esecuzione disastrosi — come scegliere un nested loop su milioni di righe pensando che siano centinaia, o ignorare un indice perfettamente adatto.\nQuando eseguirlo #PostgreSQL esegue ANALYZE automaticamente tramite l\u0026rsquo;autovacuum, ma la soglia di default (50 righe + 10% delle righe vive) può essere troppo alta per tabelle che crescono rapidamente. Situazioni in cui serve un ANALYZE manuale:\nDopo import massivi o bulk load Dopo cambiamenti significativi nella distribuzione dei dati Quando EXPLAIN ANALYZE mostra stime di cardinalità molto diverse dalle righe reali Dopo aver modificato il default_statistics_target di una colonna ","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/postgresql-analyze/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eANALYZE\u003c/strong\u003e è il comando PostgreSQL che raccoglie statistiche sulla distribuzione dei dati nelle tabelle e le salva nel catalogo \u003ccode\u003epg_statistic\u003c/code\u003e (leggibile tramite la vista \u003ccode\u003epg_stats\u003c/code\u003e). L\u0026rsquo;optimizer usa queste statistiche per stimare la cardinalità — quante righe restituirà ogni operazione — e scegliere il piano di esecuzione più efficiente.\u003c/p\u003e\n\u003ch2 id=\"cosa-raccoglie\" class=\"relative group\"\u003eCosa raccoglie \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#cosa-raccoglie\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLe statistiche raccolte da ANALYZE includono:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eMost common values\u003c/strong\u003e: i valori più frequenti per ogni colonna e la loro percentuale\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eIstogrammi di distribuzione\u003c/strong\u003e: come sono distribuiti i valori rimanenti\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eNumero di valori distinti\u003c/strong\u003e: quanti valori unici ha ogni colonna\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePercentuale di NULL\u003c/strong\u003e: quante righe hanno valore NULL per ogni colonna\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eLa qualità di queste statistiche dipende dal numero di campioni raccolti, controllato dal parametro \u003ccode\u003edefault_statistics_target\u003c/code\u003e.\u003c/p\u003e","title":"ANALYZE"},{"content":"L\u0026rsquo;Anonymous User (utente anonimo) è un account MySQL/MariaDB con username vuoto (''@'localhost') che viene creato automaticamente durante l\u0026rsquo;installazione. Non ha nome e spesso non ha password.\nCome funziona #Quando un utente si connette, MySQL cerca la corrispondenza più specifica nella tabella mysql.user. L\u0026rsquo;utente anonimo ''@'localhost' è più specifico di 'mario'@'%' per una connessione da localhost, perché 'localhost' batte '%' nella gerarchia di specificità. Di conseguenza, Mario che si connette da locale viene autenticato come utente anonimo e perde tutti i suoi privilegi.\nA cosa serve #L\u0026rsquo;utente anonimo era pensato per installazioni di sviluppo dove si voleva consentire connessioni senza credenziali. In produzione non ha alcuna utilità e rappresenta un rischio di sicurezza: può catturare connessioni destinate ad altri utenti e concedere accesso non autorizzato.\nQuando si usa #Mai in produzione. La prima operazione su qualsiasi installazione MySQL/MariaDB di produzione è verificare e rimuovere gli utenti anonimi con SELECT user, host FROM mysql.user WHERE user = '' seguito da DROP USER ''@'localhost'.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/anonymous-user/","section":"Glossario","summary":"\u003cp\u003eL\u0026rsquo;\u003cstrong\u003eAnonymous User\u003c/strong\u003e (utente anonimo) è un account MySQL/MariaDB con username vuoto (\u003ccode\u003e''@'localhost'\u003c/code\u003e) che viene creato automaticamente durante l\u0026rsquo;installazione. Non ha nome e spesso non ha password.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando un utente si connette, MySQL cerca la corrispondenza più specifica nella tabella \u003ccode\u003emysql.user\u003c/code\u003e. L\u0026rsquo;utente anonimo \u003ccode\u003e''@'localhost'\u003c/code\u003e è più specifico di \u003ccode\u003e'mario'@'%'\u003c/code\u003e per una connessione da localhost, perché \u003ccode\u003e'localhost'\u003c/code\u003e batte \u003ccode\u003e'%'\u003c/code\u003e nella gerarchia di specificità. Di conseguenza, Mario che si connette da locale viene autenticato come utente anonimo e perde tutti i suoi privilegi.\u003c/p\u003e","title":"Anonymous User"},{"content":"ASH (Active Session History) è un componente di Oracle Database che campiona lo stato di ogni sessione attiva una volta al secondo e conserva i dati in un buffer circolare in memoria (vista V$ACTIVE_SESSION_HISTORY).\nCome funziona #Ogni secondo Oracle registra per ogni sessione attiva:\nSQL in esecuzione (SQL_ID) Wait event corrente Programma e modulo chiamante Piano di esecuzione utilizzato (SQL_PLAN_HASH_VALUE) I dati più vecchi vengono scaricati automaticamente nelle tabelle AWR (DBA_HIST_ACTIVE_SESS_HISTORY) e conservati per il periodo configurato.\nA cosa serve #ASH è il microscopio del DBA: dove AWR mostra medie su intervalli orari, ASH permette di ricostruire cosa stava facendo una singola sessione in un preciso istante. È lo strumento ideale per:\nIdentificare chi sta eseguendo un SQL problematico Capire quando un problema è iniziato (al secondo) Correlare sessioni, programmi e wait event in tempo reale Quando si usa #Si usa quando il report AWR ha già identificato un SQL o un wait event dominante e si ha bisogno di dettaglio: quale sessione, quale programma, a che ora esatta. La regola empirica: AWR per capire cosa è cambiato, ASH per capire perché.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/ash/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eASH\u003c/strong\u003e (Active Session History) è un componente di Oracle Database che campiona lo stato di ogni sessione attiva una volta al secondo e conserva i dati in un buffer circolare in memoria (vista \u003ccode\u003eV$ACTIVE_SESSION_HISTORY\u003c/code\u003e).\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOgni secondo Oracle registra per ogni sessione attiva:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eSQL in esecuzione (\u003ccode\u003eSQL_ID\u003c/code\u003e)\u003c/li\u003e\n\u003cli\u003eWait event corrente\u003c/li\u003e\n\u003cli\u003eProgramma e modulo chiamante\u003c/li\u003e\n\u003cli\u003ePiano di esecuzione utilizzato (\u003ccode\u003eSQL_PLAN_HASH_VALUE\u003c/code\u003e)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eI dati più vecchi vengono scaricati automaticamente nelle tabelle AWR (\u003ccode\u003eDBA_HIST_ACTIVE_SESS_HISTORY\u003c/code\u003e) e conservati per il periodo configurato.\u003c/p\u003e","title":"ASH"},{"content":"Un Authentication Plugin è il modulo che MySQL o MariaDB usa per verificare le credenziali di un utente al momento della connessione. Ogni utente nel sistema è associato a un plugin specifico che determina come la password viene hashata, trasmessa e verificata.\nCome funziona #I plugin principali sono: mysql_native_password (default in MySQL 5.7 e MariaDB), che usa un hash SHA1 doppio; caching_sha2_password (default in MySQL 8.0+), che usa SHA-256 con caching per migliorare sicurezza e performance. Quando un client si connette, deve supportare il plugin dell\u0026rsquo;utente a cui sta tentando di autenticarsi.\nA cosa serve #La conoscenza dei plugin di autenticazione è essenziale durante le migrazioni tra versioni o tra MySQL e MariaDB. Un client che supporta solo mysql_native_password non riesce a connettersi a un utente con caching_sha2_password — e l\u0026rsquo;errore risultante è spesso criptico e difficile da diagnosticare.\nQuando si usa #Il plugin si specifica al momento della creazione dell\u0026rsquo;utente (CREATE USER ... IDENTIFIED WITH \u0026lt;plugin\u0026gt; BY 'password') oppure si può verificare e modificare con ALTER USER. Quando si scrivono script di provisioning che devono funzionare su versioni diverse di MySQL/MariaDB, è importante specificare esplicitamente il plugin.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/authentication-plugin/","section":"Glossario","summary":"\u003cp\u003eUn \u003cstrong\u003eAuthentication Plugin\u003c/strong\u003e è il modulo che MySQL o MariaDB usa per verificare le credenziali di un utente al momento della connessione. Ogni utente nel sistema è associato a un plugin specifico che determina come la password viene hashata, trasmessa e verificata.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eI plugin principali sono: \u003ccode\u003emysql_native_password\u003c/code\u003e (default in MySQL 5.7 e MariaDB), che usa un hash SHA1 doppio; \u003ccode\u003ecaching_sha2_password\u003c/code\u003e (default in MySQL 8.0+), che usa SHA-256 con caching per migliorare sicurezza e performance. Quando un client si connette, deve supportare il plugin dell\u0026rsquo;utente a cui sta tentando di autenticarsi.\u003c/p\u003e","title":"Authentication Plugin"},{"content":"L\u0026rsquo;Autovacuum è un daemon di PostgreSQL che esegue automaticamente VACUUM e ANALYZE sulle tabelle quando il numero di dead tuples supera una soglia calcolata come: threshold + scale_factor × n_live_tup. Con i default (threshold=50, scale_factor=0.2), su una tabella con 10 milioni di righe si attiva dopo 2 milioni di dead tuples.\nCome funziona #Il daemon controlla periodicamente pg_stat_user_tables e lancia un worker per ogni tabella che supera la soglia. Il numero massimo di worker simultanei è controllato da autovacuum_max_workers (default 3). Il parametro autovacuum_vacuum_cost_delay controlla quanto il vacuum rallenta sé stesso per non sovraccaricare l\u0026rsquo;I/O.\nA cosa serve #È il custode silenzioso che impedisce alle tabelle di gonfiarsi per accumulo di dead tuples. Non va mai disabilitato — è la peggior cosa che si possa fare a un PostgreSQL in produzione. Va configurato per tabella: le tabelle ad alto traffico necessitano scale_factor bassi (0.01-0.05) e cost_delay ridotti.\nCosa può andare storto #Con i default, l\u0026rsquo;autovacuum è troppo conservativo per tabelle ad alto traffico. 3 worker per decine di tabelle attive non bastano. Lo scale_factor al 20% su tabelle grandi genera milioni di dead tuples prima dell\u0026rsquo;intervento. Il tuning per-tabella con ALTER TABLE ... SET (autovacuum_vacuum_scale_factor = 0.01) è essenziale.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/autovacuum/","section":"Glossario","summary":"\u003cp\u003eL\u0026rsquo;\u003cstrong\u003eAutovacuum\u003c/strong\u003e è un daemon di PostgreSQL che esegue automaticamente VACUUM e ANALYZE sulle tabelle quando il numero di dead tuples supera una soglia calcolata come: \u003ccode\u003ethreshold + scale_factor × n_live_tup\u003c/code\u003e. Con i default (threshold=50, scale_factor=0.2), su una tabella con 10 milioni di righe si attiva dopo 2 milioni di dead tuples.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl daemon controlla periodicamente \u003ccode\u003epg_stat_user_tables\u003c/code\u003e e lancia un worker per ogni tabella che supera la soglia. Il numero massimo di worker simultanei è controllato da \u003ccode\u003eautovacuum_max_workers\u003c/code\u003e (default 3). Il parametro \u003ccode\u003eautovacuum_vacuum_cost_delay\u003c/code\u003e controlla quanto il vacuum rallenta sé stesso per non sovraccaricare l\u0026rsquo;I/O.\u003c/p\u003e","title":"Autovacuum"},{"content":"AWR (Automatic Workload Repository) è un componente integrato nel database Oracle che raccoglie automaticamente statistiche sulle performance del sistema a intervalli regolari (di default ogni 60 minuti) e le conserva per un periodo configurabile.\nCome funziona #AWR cattura snapshot periodici che includono:\nStatistiche delle sessioni e dei wait event Metriche SQL (top SQL per tempo di esecuzione, I/O, CPU) Statistiche sulle strutture di memoria (SGA, PGA) Statistiche I/O per datafile e tablespace A cosa serve #Il report AWR è lo strumento principale per diagnosticare problemi di performance in Oracle. Confrontando due snapshot è possibile identificare:\nQuery che consumano troppe risorse Cambiamenti nei piani di esecuzione Colli di bottiglia su I/O, CPU o memoria Regressioni di performance dopo deploy applicativi Quando si usa #AWR è il primo strumento da consultare quando si riceve una segnalazione di lentezza. Insieme ad ASH (Active Session History), permette di ricostruire cosa è successo nel database in un intervallo di tempo specifico, anche dopo che il problema si è risolto.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/awr/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eAWR\u003c/strong\u003e (Automatic Workload Repository) è un componente integrato nel database Oracle che raccoglie automaticamente statistiche sulle performance del sistema a intervalli regolari (di default ogni 60 minuti) e le conserva per un periodo configurabile.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eAWR cattura snapshot periodici che includono:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eStatistiche delle sessioni e dei wait event\u003c/li\u003e\n\u003cli\u003eMetriche SQL (top SQL per tempo di esecuzione, I/O, CPU)\u003c/li\u003e\n\u003cli\u003eStatistiche sulle strutture di memoria (SGA, PGA)\u003c/li\u003e\n\u003cli\u003eStatistiche I/O per datafile e tablespace\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"a-cosa-serve\" class=\"relative group\"\u003eA cosa serve \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#a-cosa-serve\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl report AWR è lo strumento principale per diagnosticare problemi di performance in Oracle. Confrontando due snapshot è possibile identificare:\u003c/p\u003e","title":"AWR"},{"content":"Il B-Tree (Balanced Tree) è la struttura dati più comune per gli indici nei database relazionali ed è il tipo di indice predefinito in PostgreSQL, MySQL e Oracle. Mantiene i dati ordinati in una struttura ad albero bilanciato che garantisce tempi di ricerca logaritmici.\nCome funziona #Un B-Tree organizza le chiavi in nodi ordinati, con ogni nodo che contiene puntatori ai nodi figli. La ricerca parte dalla radice e scende verso le foglie, dimezzando lo spazio di ricerca ad ogni livello. Per una tabella di 6 milioni di righe, un B-Tree richiede tipicamente 3-4 livelli di profondità, quindi 3-4 letture di pagina per trovare un valore.\nA cosa serve #I B-Tree sono ottimali per ricerche di uguaglianza (WHERE col = 'valore'), range (WHERE col BETWEEN x AND y), ordinamento e ricerche con prefisso (LIKE 'ABC%'). Non possono però essere usati per ricerche con wildcard iniziale (LIKE '%ABC%'), perché l\u0026rsquo;ordinamento del B-Tree non aiuta a trovare sottostringhe in posizioni arbitrarie.\nQuando si usa #Il B-Tree è la scelta giusta per la maggior parte degli indici. Quando serve una ricerca \u0026ldquo;contiene\u0026rdquo; su testo, bisogna passare a un indice GIN con l\u0026rsquo;estensione pg_trgm. La scelta tra B-Tree e GIN dipende dal tipo di query e dal profilo di carico della tabella.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/b-tree/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eB-Tree\u003c/strong\u003e (Balanced Tree) è la struttura dati più comune per gli indici nei database relazionali ed è il tipo di indice predefinito in PostgreSQL, MySQL e Oracle. Mantiene i dati ordinati in una struttura ad albero bilanciato che garantisce tempi di ricerca logaritmici.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn B-Tree organizza le chiavi in nodi ordinati, con ogni nodo che contiene puntatori ai nodi figli. La ricerca parte dalla radice e scende verso le foglie, dimezzando lo spazio di ricerca ad ogni livello. Per una tabella di 6 milioni di righe, un B-Tree richiede tipicamente 3-4 livelli di profondità, quindi 3-4 letture di pagina per trovare un valore.\u003c/p\u003e","title":"B-Tree"},{"content":"Una Bicicletta Pieghevole è una bicicletta progettata per ripiegarsi in dimensioni compatte (tipicamente 60×55×25 cm) in pochi secondi, diventando trasportabile come un bagaglio. La Brompton è il modello più noto, con meccanismo di piegatura in 10-20 secondi.\nCome funziona #Un sistema di cerniere e sganci rapidi permette di piegare telaio, manubrio e pedali in un pacchetto compatto. Una volta ripiegata, si porta in ufficio sotto la scrivania, si sale in metro o si mette nel bagagliaio. Nella versione elettrica, combina i vantaggi della pedalata assistita con la portabilità totale.\nA cosa serve #Elimina completamente il problema del parcheggio — che a Roma può costare 35€ al giorno e un\u0026rsquo;ora e mezza di ricerca. Non c\u0026rsquo;è rischio di furto perché la bici è sempre con te. E nei giorni di pioggia forte, si piega e si porta in metro senza problemi.\nPerché è critico #La bicicletta pieghevole è il \u0026ldquo;superpotere\u0026rdquo; che rende il commuting in bici praticabile anche per chi non ha un parcheggio dedicato, chi deve prendere i mezzi pubblici per parte del tragitto, o chi lavora in un ufficio senza rastrelliera. È la soluzione all\u0026rsquo;ultimo miglio che l\u0026rsquo;auto non può offrire.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/bicicletta-pieghevole/","section":"Glossario","summary":"\u003cp\u003eUna \u003cstrong\u003eBicicletta Pieghevole\u003c/strong\u003e è una bicicletta progettata per ripiegarsi in dimensioni compatte (tipicamente 60×55×25 cm) in pochi secondi, diventando trasportabile come un bagaglio. La Brompton è il modello più noto, con meccanismo di piegatura in 10-20 secondi.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn sistema di cerniere e sganci rapidi permette di piegare telaio, manubrio e pedali in un pacchetto compatto. Una volta ripiegata, si porta in ufficio sotto la scrivania, si sale in metro o si mette nel bagagliaio. Nella versione elettrica, combina i vantaggi della pedalata assistita con la portabilità totale.\u003c/p\u003e","title":"Bicicletta Pieghevole"},{"content":"Il binary log (o binlog) è un registro sequenziale in formato binario in cui MySQL scrive tutti gli eventi che modificano i dati: INSERT, UPDATE, DELETE e operazioni DDL. I file sono numerati progressivamente (mysql-bin.000001, mysql-bin.000002, ecc.) e gestiti tramite un file indice.\nCome funziona #Da MySQL 8.0 il binary log è abilitato di default tramite il parametro log_bin. MySQL crea un nuovo file binlog quando il server si avvia, quando il file corrente raggiunge max_binlog_size, o quando si esegue FLUSH BINARY LOGS. Supporta tre formati di registrazione: STATEMENT (registra le istruzioni SQL), ROW (registra le modifiche riga per riga) e MIXED (scelta automatica).\nA cosa serve #Il binary log ha due funzioni fondamentali:\nReplica: in un\u0026rsquo;architettura master-slave, lo slave legge i binlog del master per replicare le stesse operazioni Point-in-time recovery: dopo un restore da backup, i binlog permettono di riapplicare le modifiche fino a un momento preciso Quando si usa #Il binary log è attivo di default su qualsiasi installazione MySQL 8.0+. La gestione attiva (retention, purge, monitoraggio dello spazio) è necessaria per evitare che i file accumulati riempiano il disco. Il comando PURGE BINARY LOGS è il modo corretto per eliminare i file obsoleti.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/binary-log/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003ebinary log\u003c/strong\u003e (o binlog) è un registro sequenziale in formato binario in cui MySQL scrive tutti gli eventi che modificano i dati: INSERT, UPDATE, DELETE e operazioni DDL. I file sono numerati progressivamente (\u003ccode\u003emysql-bin.000001\u003c/code\u003e, \u003ccode\u003emysql-bin.000002\u003c/code\u003e, ecc.) e gestiti tramite un file indice.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eDa MySQL 8.0 il binary log è abilitato di default tramite il parametro \u003ccode\u003elog_bin\u003c/code\u003e. MySQL crea un nuovo file binlog quando il server si avvia, quando il file corrente raggiunge \u003ccode\u003emax_binlog_size\u003c/code\u003e, o quando si esegue \u003ccode\u003eFLUSH BINARY LOGS\u003c/code\u003e. Supporta tre formati di registrazione: STATEMENT (registra le istruzioni SQL), ROW (registra le modifiche riga per riga) e MIXED (scelta automatica).\u003c/p\u003e","title":"Binary log"},{"content":"Il Bloat è l\u0026rsquo;accumulo di spazio morto all\u0026rsquo;interno di una tabella o di un indice PostgreSQL, causato da dead tuples non ancora rimossi dal VACUUM. Una tabella con il 50% di bloat occupa il doppio dello spazio necessario e costringe le scansioni sequenziali a leggere il doppio delle pagine.\nCome funziona #Il bloat si misura confrontando la dimensione effettiva della tabella con la dimensione attesa basata sulle righe vive. L\u0026rsquo;estensione pgstattuple fornisce il campo dead_tuple_percent. Un bloat sopra il 20-30% è un segnale di allarme; sopra il 50% è un\u0026rsquo;emergenza.\nA cosa serve #Monitorare il bloat è essenziale per capire se l\u0026rsquo;autovacuum sta tenendo il passo. La query pg_stat_user_tables con n_dead_tup e last_autovacuum è il primo strumento diagnostico. Se il bloat è fuori controllo, pg_repack ricostruisce la tabella online senza lock esclusivi prolungati — al contrario di VACUUM FULL.\nCosa può andare storto #VACUUM normale recupera lo spazio dei dead tuples ma non compatta la tabella — lo spazio frammentato resta. Se il bloat raggiunge il 50-70%, il VACUUM non basta più. Le opzioni sono VACUUM FULL (lock esclusivo, blocca tutto) o pg_repack (online, ma richiede installazione). La vera soluzione è non arrivarci, con un autovacuum ben configurato.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/bloat/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eBloat\u003c/strong\u003e è l\u0026rsquo;accumulo di spazio morto all\u0026rsquo;interno di una tabella o di un indice PostgreSQL, causato da dead tuples non ancora rimossi dal VACUUM. Una tabella con il 50% di bloat occupa il doppio dello spazio necessario e costringe le scansioni sequenziali a leggere il doppio delle pagine.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl bloat si misura confrontando la dimensione effettiva della tabella con la dimensione attesa basata sulle righe vive. L\u0026rsquo;estensione \u003ccode\u003epgstattuple\u003c/code\u003e fornisce il campo \u003ccode\u003edead_tuple_percent\u003c/code\u003e. Un bloat sopra il 20-30% è un segnale di allarme; sopra il 50% è un\u0026rsquo;emergenza.\u003c/p\u003e","title":"Bloat"},{"content":"Un Branch (ramo) è una linea di sviluppo indipendente in un repository Git. Ogni branch contiene una copia del codice su cui si può lavorare senza influenzare il branch principale (main) o il lavoro di altri sviluppatori.\nCome funziona #Quando uno sviluppatore crea un branch (es. fix/issue-234-errore-calcolo), Git crea un puntatore alla versione corrente del codice. Da quel momento, le modifiche fatte sul branch restano isolate. Al termine del lavoro, le modifiche vengono proposte al team tramite Pull Request e, dopo approvazione, unite (merged) nel branch principale.\nA cosa serve #I branch eliminano il problema delle sovrascritture accidentali e dei conflitti non gestiti. Ogni sviluppatore lavora nella propria area isolata: non sovrascrive il lavoro degli altri e non rompe il codice funzionante. Il branch principale resta sempre in uno stato \u0026ldquo;buono\u0026rdquo; perché riceve solo codice approvato.\nQuando si usa #Un branch si crea per ogni task, bug fix o funzionalità. La convenzione di naming aiuta a identificare lo scopo: fix/ per bug, feature/ per nuove funzionalità, hotfix/ per correzioni urgenti. Il branch viene eliminato dopo il merge per mantenere il repository pulito.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/branch/","section":"Glossario","summary":"\u003cp\u003eUn \u003cstrong\u003eBranch\u003c/strong\u003e (ramo) è una linea di sviluppo indipendente in un repository Git. Ogni branch contiene una copia del codice su cui si può lavorare senza influenzare il branch principale (main) o il lavoro di altri sviluppatori.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando uno sviluppatore crea un branch (es. \u003ccode\u003efix/issue-234-errore-calcolo\u003c/code\u003e), Git crea un puntatore alla versione corrente del codice. Da quel momento, le modifiche fatte sul branch restano isolate. Al termine del lavoro, le modifiche vengono proposte al team tramite Pull Request e, dopo approvazione, unite (merged) nel branch principale.\u003c/p\u003e","title":"Branch"},{"content":"La Brompton è una bicicletta pieghevole prodotta a Londra dal 1975, considerata il riferimento mondiale nella categoria. Si piega in 10-20 secondi raggiungendo dimensioni di circa 58×56×27 cm — abbastanza compatta da stare sotto una scrivania o nel bagagliaio di un\u0026rsquo;utilitaria.\nCome funziona #Il meccanismo brevettato permette di piegare la bici in tre movimenti: telaio, manubrio e sella. Nella versione elettrica (Brompton Electric), un motore nel mozzo anteriore fornisce pedalata assistita fino a 25 km/h con un\u0026rsquo;autonomia di 40-70 km. La batteria è rimovibile e si ricarica in 4 ore.\nA cosa serve #È la soluzione ideale per il pendolarismo multimodale: si pedala fino alla stazione, si piega, si sale in metro o treno, si apre e si pedala fino all\u0026rsquo;ufficio. Una volta arrivati, si ripone sotto la scrivania. Zero parcheggio, zero furto, zero vincoli.\nPerché è critico #Nel confronto diretto auto vs Brompton a Roma (Appio Latino → Prati), la Brompton impiega 18 minuti contro i 50 dell\u0026rsquo;auto più 90 minuti di parcheggio. Costo giornaliero: 0€ contro 35€. La Brompton si ripaga in meno di un anno di risparmio sul solo parcheggio.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/brompton/","section":"Glossario","summary":"\u003cp\u003eLa \u003cstrong\u003eBrompton\u003c/strong\u003e è una bicicletta pieghevole prodotta a Londra dal 1975, considerata il riferimento mondiale nella categoria. Si piega in 10-20 secondi raggiungendo dimensioni di circa 58×56×27 cm — abbastanza compatta da stare sotto una scrivania o nel bagagliaio di un\u0026rsquo;utilitaria.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl meccanismo brevettato permette di piegare la bici in tre movimenti: telaio, manubrio e sella. Nella versione elettrica (Brompton Electric), un motore nel mozzo anteriore fornisce pedalata assistita fino a 25 km/h con un\u0026rsquo;autonomia di 40-70 km. La batteria è rimovibile e si ricarica in 4 ore.\u003c/p\u003e","title":"Brompton"},{"content":"BYOL (Bring Your Own License) è un programma Oracle che consente alle aziende di trasferire le licenze software acquistate per l\u0026rsquo;infrastruttura on-premises verso Oracle Cloud Infrastructure (OCI), senza dover acquistare nuove licenze cloud.\nCome funziona #Quando un\u0026rsquo;azienda ha già licenze Oracle — tipicamente Enterprise Edition con opzioni come RAC, Data Guard o Partitioning — può \u0026ldquo;portarle con sé\u0026rdquo; nella migrazione a OCI. Il contratto di supporto (Software Update License \u0026amp; Support) viene mantenuto, e le licenze vengono associate alle risorse cloud invece che ai server fisici.\nSu OCI, ogni OCPU corrisponde a un processor license, con un rapporto 1:1 trasparente. Questo rende il calcolo prevedibile e conforme alle policy di licensing Oracle.\nPerché è importante nelle migrazioni #Il BYOL è spesso il fattore decisivo nella scelta di OCI rispetto ad altri cloud provider. Su AWS o Azure, Oracle applica regole di licensing diverse: ogni vCPU conta come mezzo processore, e le opzioni come RAC non sono supportate o richiedono licenze aggiuntive. Un audit Oracle su un cloud non-OCI può trasformare un apparente risparmio in un costo imprevisto molto significativo.\nCosa copre # Oracle Database (tutte le edizioni) Opzioni del database (RAC, Data Guard, Partitioning, Advanced Compression, ecc.) Oracle Middleware e altri prodotti Oracle con licenze idonee Il BYOL non è automatico: va richiesto e configurato al momento del provisioning delle risorse OCI, specificando le licenze esistenti nel contratto.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/byol/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eBYOL\u003c/strong\u003e (Bring Your Own License) è un programma Oracle che consente alle aziende di trasferire le licenze software acquistate per l\u0026rsquo;infrastruttura on-premises verso Oracle Cloud Infrastructure (OCI), senza dover acquistare nuove licenze cloud.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando un\u0026rsquo;azienda ha già licenze Oracle — tipicamente Enterprise Edition con opzioni come RAC, Data Guard o Partitioning — può \u0026ldquo;portarle con sé\u0026rdquo; nella migrazione a OCI. Il contratto di supporto (Software Update License \u0026amp; Support) viene mantenuto, e le licenze vengono associate alle risorse cloud invece che ai server fisici.\u003c/p\u003e","title":"BYOL"},{"content":"Il Carbon Footprint (impronta di carbonio) è la quantità totale di gas serra — principalmente CO₂ — emessi direttamente o indirettamente da un\u0026rsquo;attività, un prodotto o un individuo, espressa in tonnellate di CO₂ equivalente.\nCome funziona #Per il pendolarismo urbano, il calcolo è diretto: un\u0026rsquo;auto ferma nel traffico di Roma produce in media 120-150 g di CO₂ per chilometro. Nel traffico congestionato anche di più, perché il motore gira al minimo consumando senza muoversi. Una bicicletta produce zero emissioni dirette.\nA cosa serve #Quantifica l\u0026rsquo;impatto ambientale delle scelte di mobilità. Se solo il 10% dei pendolari romani passasse alla bici, si risparmierebbero circa 150.000 tonnellate di CO₂ all\u0026rsquo;anno — l\u0026rsquo;equivalente di piantare 7 milioni di alberi. Non è idealismo, è aritmetica.\nPerché è critico #Il carbon footprint del pendolarismo è un costo esternalizzato che nessuno paga direttamente ma che tutti subiscono: inquinamento dell\u0026rsquo;aria, cambiamento climatico, costi sanitari. La scelta tra auto e bici non è solo personale — ha un impatto collettivo misurabile.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/carbon-footprint/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eCarbon Footprint\u003c/strong\u003e (impronta di carbonio) è la quantità totale di gas serra — principalmente CO₂ — emessi direttamente o indirettamente da un\u0026rsquo;attività, un prodotto o un individuo, espressa in tonnellate di CO₂ equivalente.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003ePer il pendolarismo urbano, il calcolo è diretto: un\u0026rsquo;auto ferma nel traffico di Roma produce in media 120-150 g di CO₂ per chilometro. Nel traffico congestionato anche di più, perché il motore gira al minimo consumando senza muoversi. Una bicicletta produce zero emissioni dirette.\u003c/p\u003e","title":"Carbon Footprint"},{"content":"CDC (Change Data Capture) è una tecnica per intercettare le modifiche ai dati (INSERT, UPDATE, DELETE) nel momento in cui avvengono e propagarle verso altri sistemi in tempo reale o quasi reale. A differenza degli approcci batch tradizionali (ETL periodici), il CDC cattura i cambiamenti in modo continuo e incrementale.\nCome funziona #L\u0026rsquo;approccio più diffuso è il log-based CDC: un componente esterno legge i log delle transazioni del database (binary log in MySQL, WAL in PostgreSQL, redo log in Oracle) e converte gli eventi in un flusso di dati consumabile da altri sistemi. Strumenti come Debezium, Maxwell e Canal implementano questo approccio per MySQL leggendo direttamente i binary log.\nA cosa serve #Il CDC è usato per:\nSincronizzare dati tra database diversi in tempo reale Alimentare data warehouse e data lake con aggiornamenti incrementali Popolare cache e indici di ricerca (Elasticsearch, Redis) Implementare architetture event-driven e microservizi Quando si usa #Il CDC richiede che il binary log sia attivo e in formato ROW (che registra le modifiche riga per riga). Disabilitare i binary log o usare il formato STATEMENT elimina la possibilità di utilizzare strumenti di CDC, rendendo impossibile l\u0026rsquo;integrazione in tempo reale con sistemi esterni.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/cdc/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eCDC\u003c/strong\u003e (Change Data Capture) è una tecnica per intercettare le modifiche ai dati (INSERT, UPDATE, DELETE) nel momento in cui avvengono e propagarle verso altri sistemi in tempo reale o quasi reale. A differenza degli approcci batch tradizionali (ETL periodici), il CDC cattura i cambiamenti in modo continuo e incrementale.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eL\u0026rsquo;approccio più diffuso è il \u003cstrong\u003elog-based CDC\u003c/strong\u003e: un componente esterno legge i log delle transazioni del database (binary log in MySQL, WAL in PostgreSQL, redo log in Oracle) e converte gli eventi in un flusso di dati consumabile da altri sistemi. Strumenti come Debezium, Maxwell e Canal implementano questo approccio per MySQL leggendo direttamente i binary log.\u003c/p\u003e","title":"CDC"},{"content":"La chiave surrogata (surrogate key) è un identificativo numerico sequenziale generato internamente dal data warehouse, senza alcun significato di business. È distinta dalla chiave naturale — quella che arriva dal sistema sorgente (es. il codice cliente, il numero di matricola).\nPerché serve #Nella SCD Tipo 2, lo stesso cliente può avere più righe nella tabella dimensionale — una per ogni versione storica. La chiave naturale (cliente_id) non è più univoca, quindi serve un identificativo che distingua ogni singola versione: la chiave surrogata (cliente_key).\nCome funziona #Viene generata tipicamente da una sequence (Oracle) o una colonna SERIAL/IDENTITY (PostgreSQL, MySQL). Non viene mai esposta agli utenti finali e non ha significato al di fuori del data warehouse.\nLa fact table usa la chiave surrogata come foreign key, puntando alla versione specifica della dimensione valida al momento del fatto. Questo garantisce che ogni transazione sia associata al contesto dimensionale corretto per quel momento nel tempo.\nVantaggi # Permette il versioning delle dimensioni (SCD Tipo 2) I join tra fact e dimension sono su interi, quindi veloci Isola il DWH dai cambiamenti nelle chiavi dei sistemi sorgente Supporta il caricamento da fonti multiple con chiavi naturali potenzialmente duplicate ","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/chiave-surrogata/","section":"Glossario","summary":"\u003cp\u003eLa \u003cstrong\u003echiave surrogata\u003c/strong\u003e (surrogate key) è un identificativo numerico sequenziale generato internamente dal data warehouse, senza alcun significato di business. È distinta dalla chiave naturale — quella che arriva dal sistema sorgente (es. il codice cliente, il numero di matricola).\u003c/p\u003e\n\u003ch2 id=\"perché-serve\" class=\"relative group\"\u003ePerché serve \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#perch%c3%a9-serve\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eNella SCD Tipo 2, lo stesso cliente può avere più righe nella tabella dimensionale — una per ogni versione storica. La chiave naturale (\u003ccode\u003ecliente_id\u003c/code\u003e) non è più univoca, quindi serve un identificativo che distingua ogni singola versione: la chiave surrogata (\u003ccode\u003ecliente_key\u003c/code\u003e).\u003c/p\u003e","title":"Chiave surrogata"},{"content":"Il churn di una tabella è la misura di quanto i suoi dati cambiano dopo l\u0026rsquo;inserimento. Una tabella con alto churn subisce frequenti UPDATE e DELETE; una tabella con basso churn è prevalentemente append-only (solo INSERT).\nCome funziona #In PostgreSQL, ogni UPDATE crea una nuova versione della riga (a causa del modello MVCC) e la vecchia versione diventa una dead tuple. Le DELETE creano anch\u0026rsquo;esse dead tuples. Più alto è il churn, più lavoro devono fare VACUUM e gli indici per mantenere le performance. Un indice GIN su una tabella ad alto churn può degradare significativamente le performance di scrittura.\nA cosa serve #Valutare il churn prima di creare un indice è essenziale per evitare di risolvere un problema di lettura creandone uno di scrittura. Su una tabella append-only (zero UPDATE, zero DELETE, zero dead tuples), un indice GIN ha un impatto minimo sulle scritture. Su una tabella ad alto churn, lo stesso indice potrebbe diventare un collo di bottiglia.\nQuando si usa #Il churn si analizza verificando le statistiche della tabella: numero di UPDATE e DELETE giornalieri, dead tuples, frequenza di VACUUM. In PostgreSQL, pg_stat_user_tables fornisce queste metriche. La decisione di aggiungere un indice GIN o trigram dovrebbe sempre partire da questa analisi.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/churn/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003echurn\u003c/strong\u003e di una tabella è la misura di quanto i suoi dati cambiano dopo l\u0026rsquo;inserimento. Una tabella con alto churn subisce frequenti UPDATE e DELETE; una tabella con basso churn è prevalentemente append-only (solo INSERT).\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIn PostgreSQL, ogni UPDATE crea una nuova versione della riga (a causa del modello MVCC) e la vecchia versione diventa una dead tuple. Le DELETE creano anch\u0026rsquo;esse dead tuples. Più alto è il churn, più lavoro devono fare VACUUM e gli indici per mantenere le performance. Un indice GIN su una tabella ad alto churn può degradare significativamente le performance di scrittura.\u003c/p\u003e","title":"Churn"},{"content":"COALESCE è una funzione SQL standard che accetta una lista di espressioni e restituisce la prima che non è NULL. Se tutte le espressioni sono NULL, restituisce NULL.\nSintassi #COALESCE(espressione1, espressione2, espressione3, ...) Equivale a una catena di CASE WHEN:\nCASE WHEN espressione1 IS NOT NULL THEN espressione1 WHEN espressione2 IS NOT NULL THEN espressione2 WHEN espressione3 IS NOT NULL THEN espressione3 ELSE NULL END Uso nelle gerarchie #Nel contesto delle ragged hierarchies, COALESCE viene spesso usata per riempire i livelli mancanti:\nCOALESCE(top_group_name, group_name, client_name) AS top_group_name Questa operazione funziona come workaround nei report, ma ha limiti importanti: va ripetuta in ogni query, non distingue i valori originali da quelli di fallback, e complica il codice.\nAlternative per database # Oracle: NVL(a, b) per due valori, COALESCE per più di due MySQL: IFNULL(a, b) per due valori, COALESCE per più di due PostgreSQL: solo COALESCE (standard SQL) Approccio consigliato nel DWH #Nel data warehouse, è preferibile usare COALESCE nell\u0026rsquo;ETL per popolare la tabella dimensionale con valori NOT NULL (self-parenting), piuttosto che usarla ripetutamente nei report. La logica di gestione dei NULL deve stare nel modello, non nella presentazione.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/coalesce/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eCOALESCE\u003c/strong\u003e è una funzione SQL standard che accetta una lista di espressioni e restituisce la prima che non è NULL. Se tutte le espressioni sono NULL, restituisce NULL.\u003c/p\u003e\n\u003ch2 id=\"sintassi\" class=\"relative group\"\u003eSintassi \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#sintassi\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eCOALESCE\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eespressione1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eespressione2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eespressione3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e...)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eEquivale a una catena di CASE WHEN:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eCASE\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eWHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eespressione1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eIS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNOT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNULL\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eTHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eespressione1\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e     \u003c/span\u003e\u003cspan class=\"k\"\u003eWHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eespressione2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eIS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNOT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNULL\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eTHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eespressione2\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e     \u003c/span\u003e\u003cspan class=\"k\"\u003eWHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eespressione3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eIS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNOT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNULL\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eTHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eespressione3\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e     \u003c/span\u003e\u003cspan class=\"k\"\u003eELSE\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNULL\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eEND\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"uso-nelle-gerarchie\" class=\"relative group\"\u003eUso nelle gerarchie \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#uso-nelle-gerarchie\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eNel contesto delle ragged hierarchies, COALESCE viene spesso usata per riempire i livelli mancanti:\u003c/p\u003e","title":"COALESCE"},{"content":"La Code Review è la pratica per cui un collega esamina il codice scritto da un altro sviluppatore prima che venga incorporato nel branch principale. Su GitHub avviene dentro le Pull Request.\nCome funziona #Lo sviluppatore apre una Pull Request con le sue modifiche. Un reviewer assegnato esamina il diff del codice, lascia commenti, suggerisce miglioramenti e alla fine approva o richiede modifiche. Il processo è asincrono: non servono riunioni, il review avviene sullo strumento. Solo dopo l\u0026rsquo;approvazione il codice viene fuso nel branch principale.\nA cosa serve #La code review cattura bug che i test automatici non trovano, migliora la qualità del codice, e — aspetto spesso sottovalutato — diffonde la conoscenza del codebase nel team. Se solo una persona conosce un modulo e se ne va, il progetto ha un problema. Con le code review, almeno due persone conoscono ogni pezzo di codice.\nQuando si usa #Su ogni Pull Request, senza eccezioni. Non è una formalità: è un investimento in qualità. Il tempo speso in review è sempre inferiore al tempo che si spenderebbe per correggere bug in produzione scoperti troppo tardi.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/code-review/","section":"Glossario","summary":"\u003cp\u003eLa \u003cstrong\u003eCode Review\u003c/strong\u003e è la pratica per cui un collega esamina il codice scritto da un altro sviluppatore prima che venga incorporato nel branch principale. Su GitHub avviene dentro le Pull Request.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLo sviluppatore apre una Pull Request con le sue modifiche. Un reviewer assegnato esamina il diff del codice, lascia commenti, suggerisce miglioramenti e alla fine approva o richiede modifiche. Il processo è asincrono: non servono riunioni, il review avviene sullo strumento. Solo dopo l\u0026rsquo;approvazione il codice viene fuso nel branch principale.\u003c/p\u003e","title":"Code Review"},{"content":"La Compliance (conformità normativa) è l\u0026rsquo;aderenza di un\u0026rsquo;organizzazione alle leggi, ai regolamenti e agli standard di settore applicabili alla sua attività. Nel contesto AI, include GDPR, regolamenti bancari (SOX, PCI-DSS), normative sanitarie e policy interne sull\u0026rsquo;uso dei dati.\nCome funziona #La compliance si verifica attraverso audit, controlli documentali e monitoraggio continuo. Per i progetti AI, richiede la tracciabilità dei dati usati per il training, la documentazione delle decisioni automatizzate e la capacità di spiegare come il modello è arrivato a un determinato output (explainability).\nA cosa serve #Garantisce che l\u0026rsquo;organizzazione operi entro i confini legali e regolamentari. In un progetto AI, la compliance non è un optional — è un vincolo progettuale. Un modello addestrato su dati soggetti a GDPR senza consenso non è solo un rischio tecnico, è un illecito.\nPerché è critico #Nel triangolo Governance-Compliance-Automazione, la compliance è il vertice che non può mai essere sacrificato. L\u0026rsquo;AI Manager deve garantire che ogni automazione rispetti i vincoli normativi — e questo richiede una comprensione profonda sia della tecnologia sia del contesto regolamentare. Non basta che l\u0026rsquo;AI funzioni: deve funzionare nel rispetto delle regole.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/compliance/","section":"Glossario","summary":"\u003cp\u003eLa \u003cstrong\u003eCompliance\u003c/strong\u003e (conformità normativa) è l\u0026rsquo;aderenza di un\u0026rsquo;organizzazione alle leggi, ai regolamenti e agli standard di settore applicabili alla sua attività. Nel contesto AI, include GDPR, regolamenti bancari (SOX, PCI-DSS), normative sanitarie e policy interne sull\u0026rsquo;uso dei dati.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa compliance si verifica attraverso audit, controlli documentali e monitoraggio continuo. Per i progetti AI, richiede la tracciabilità dei dati usati per il training, la documentazione delle decisioni automatizzate e la capacità di spiegare come il modello è arrivato a un determinato output (explainability).\u003c/p\u003e","title":"Compliance"},{"content":"CTAS (Create Table As Select) è un comando SQL Oracle che crea una nuova tabella e la popola in un\u0026rsquo;unica operazione con i risultati di una SELECT. È la tecnica standard per migrare dati da una struttura all\u0026rsquo;altra su tabelle di grandi dimensioni.\nCome funziona #Il comando combina DDL e DML: crea la tabella con la struttura derivata dalla SELECT e inserisce i dati in un unico passaggio. Con l\u0026rsquo;hint PARALLEL e la modalità NOLOGGING, la copia di centinaia di GB può completarsi in poche ore. Dopo la copia, si rinomina la tabella originale, si rinomina la nuova, e il downtime è limitato ai pochi secondi del rename.\nA cosa serve #CTAS è fondamentale quando serve ristrutturare una tabella senza poter usare ALTER TABLE direttamente — ad esempio per aggiungere il partitioning a una tabella esistente con miliardi di righe. Permette di lavorare sulla nuova struttura mentre il sistema è attivo sulla vecchia.\nQuando si usa #Si usa per migrazioni a tabelle partizionate, per riorganizzare dati frammentati, e per creare copie di tabelle con strutture diverse. In produzione, va sempre combinato con NOLOGGING (per ridurre i redo log) e seguito da un backup RMAN immediato.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/ctas/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eCTAS\u003c/strong\u003e (Create Table As Select) è un comando SQL Oracle che crea una nuova tabella e la popola in un\u0026rsquo;unica operazione con i risultati di una SELECT. È la tecnica standard per migrare dati da una struttura all\u0026rsquo;altra su tabelle di grandi dimensioni.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl comando combina DDL e DML: crea la tabella con la struttura derivata dalla SELECT e inserisce i dati in un unico passaggio. Con l\u0026rsquo;hint \u003ccode\u003ePARALLEL\u003c/code\u003e e la modalità \u003ccode\u003eNOLOGGING\u003c/code\u003e, la copia di centinaia di GB può completarsi in poche ore. Dopo la copia, si rinomina la tabella originale, si rinomina la nuova, e il downtime è limitato ai pochi secondi del rename.\u003c/p\u003e","title":"CTAS"},{"content":"Il cutover è il momento in cui un sistema di produzione viene spostato dalla vecchia infrastruttura alla nuova. È la fase più visibile di una migrazione — quella che tutti ricordano, nel bene o nel male.\nAnatomia di un cutover #Un cutover ben pianificato segue un runbook dettagliato con passi numerati, tempi stimati, criteri di successo e procedure di rollback per ogni passo. I componenti tipici:\nStop applicativo — chiusura delle connessioni e verifica che nessuna sessione sia attiva Sincronizzazione finale — in una migrazione Data Guard, verifica che transport lag e apply lag siano a zero Switchover/migrazione — l\u0026rsquo;operazione tecnica che trasferisce il servizio Validazione — test di connettività, query di verifica, test funzionali Apertura graduale — riammissione progressiva degli utenti Downtime e finestre #Il downtime di un cutover è il tempo tra la disconnessione dell\u0026rsquo;ultimo utente e la riconnessione del primo. Con Data Guard switchover, il downtime può essere dell\u0026rsquo;ordine di minuti. Con Data Pump, può essere di ore o giorni.\nLa finestra di cutover si pianifica nei momenti di minor utilizzo: notti, weekend, festività. Ma \u0026ldquo;minor utilizzo\u0026rdquo; non significa \u0026ldquo;zero utilizzo\u0026rdquo; — in aziende manifatturiere con turni h24, non esiste un momento in cui il database non serve a nessuno.\nRollback #Ogni cutover deve avere un piano di rollback. Con Data Guard, il rollback è un secondo switchover — relativamente semplice. Con Data Pump, il rollback significa riavviare il database originale e accettare la perdita delle transazioni avvenute dopo l\u0026rsquo;inizio della migrazione. La qualità del piano di rollback è inversamente proporzionale alla probabilità di doverlo usare — ma guai a non averlo.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/cutover/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003ecutover\u003c/strong\u003e è il momento in cui un sistema di produzione viene spostato dalla vecchia infrastruttura alla nuova. È la fase più visibile di una migrazione — quella che tutti ricordano, nel bene o nel male.\u003c/p\u003e\n\u003ch2 id=\"anatomia-di-un-cutover\" class=\"relative group\"\u003eAnatomia di un cutover \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#anatomia-di-un-cutover\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn cutover ben pianificato segue un runbook dettagliato con passi numerati, tempi stimati, criteri di successo e procedure di rollback per ogni passo. I componenti tipici:\u003c/p\u003e","title":"Cutover"},{"content":"Il Daily Standup è una riunione quotidiana breve (massimo 15 minuti) in cui ogni membro del team risponde a tre domande: cosa ho fatto ieri, cosa farò oggi, c\u0026rsquo;è qualcosa che mi blocca. Lo scopo è sincronizzare il team, non risolvere problemi.\nCome funziona #Ogni persona ha circa due minuti per il proprio aggiornamento. I problemi vengono segnalati ma non discussi: la risoluzione avviene dopo, tra le persone coinvolte. Il vincolo temporale è ciò che rende lo standup efficace — senza di esso, degenera in una riunione di status da 45 minuti.\nA cosa serve #Mantiene il team allineato sullo stato del progetto, fa emergere i blocchi prima che diventino critici e crea un ritmo quotidiano che dà struttura al lavoro. Uno standup ben gestito sostituisce decine di email e messaggi Slack.\nCosa può andare storto #Il pattern di degenerazione è prevedibile: la prima settimana dura 15 minuti, la terza 35, la quarta il team inizia a saltarlo. Le cause più comuni sono i \u0026ldquo;thread killer\u0026rdquo; (discussioni tecniche tra due persone mentre gli altri aspettano), i demo improvvisati e i manager che fanno domande di approfondimento.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/daily-standup/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eDaily Standup\u003c/strong\u003e è una riunione quotidiana breve (massimo 15 minuti) in cui ogni membro del team risponde a tre domande: cosa ho fatto ieri, cosa farò oggi, c\u0026rsquo;è qualcosa che mi blocca. Lo scopo è sincronizzare il team, non risolvere problemi.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOgni persona ha circa due minuti per il proprio aggiornamento. I problemi vengono segnalati ma non discussi: la risoluzione avviene dopo, tra le persone coinvolte. Il vincolo temporale è ciò che rende lo standup efficace — senza di esso, degenera in una riunione di status da 45 minuti.\u003c/p\u003e","title":"Daily Standup"},{"content":"La Data Governance è l\u0026rsquo;insieme di politiche, processi, ruoli e standard che un\u0026rsquo;organizzazione adotta per garantire che i propri dati siano accurati, sicuri, conformi alle normative e utilizzati in modo coerente.\nCome funziona #Definisce chi è responsabile dei dati (data owner, data steward), quali regole di qualità applicare, come classificare i dati per sensibilità e come tracciare la loro provenienza (data lineage). In un contesto AI, include anche la verifica della provenienza e qualità dei dati usati per il training dei modelli.\nA cosa serve #Senza data governance, un\u0026rsquo;organizzazione non sa quali dati ha, dove sono, chi può accedervi e se sono affidabili. In progetti con componenti AI, la governance è il prerequisito per evitare che i modelli vengano addestrati su dati sporchi, non autorizzati o soggetti a vincoli normativi come il GDPR.\nPerché è critico #In ogni progetto AI in ambito regolamentato, il triangolo Governance-Compliance-Automazione deve restare in equilibrio. Un\u0026rsquo;automazione AI efficiente che viola le policy di data governance è un rischio. Una governance perfetta che blocca l\u0026rsquo;automazione ferma il progetto. L\u0026rsquo;AI Manager tiene in equilibrio questi tre vertici.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/data-governance/","section":"Glossario","summary":"\u003cp\u003eLa \u003cstrong\u003eData Governance\u003c/strong\u003e è l\u0026rsquo;insieme di politiche, processi, ruoli e standard che un\u0026rsquo;organizzazione adotta per garantire che i propri dati siano accurati, sicuri, conformi alle normative e utilizzati in modo coerente.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eDefinisce chi è responsabile dei dati (data owner, data steward), quali regole di qualità applicare, come classificare i dati per sensibilità e come tracciare la loro provenienza (data lineage). In un contesto AI, include anche la verifica della provenienza e qualità dei dati usati per il training dei modelli.\u003c/p\u003e","title":"Data Governance"},{"content":"Data Guard è la tecnologia Oracle che mantiene una o più copie sincronizzate (standby) di un database di produzione (primario). Lo standby riceve e applica continuamente i redo log generati dal primario, rimanendo allineato in tempo reale o quasi.\nCome funziona #Il primario genera redo log con ogni transazione. Questi log vengono trasmessi allo standby via rete, dove vengono applicati in due modi possibili:\nPhysical standby: applica i redo a livello di blocco (replica esatta, byte per byte) Logical standby: ricostruisce le istruzioni SQL dai redo e le riesegue In caso di guasto del primario, lo standby può diventare il nuovo primario tramite switchover (pianificato) o failover (di emergenza).\nActive Data Guard #La variante Active Data Guard permette di aprire lo standby in sola lettura mentre continua ad applicare i redo. Questo consente di usarlo per report, backup e query analitiche, alleggerendo il carico del primario.\nModalità di protezione # Modalità Comportamento Data loss MaxPerformance Replica asincrona, nessun impatto sulle performance del primario Possibile (pochi secondi) MaxAvailability Replica sincrona, degrada a MaxPerformance se lo standby non è raggiungibile Zero in condizioni normali MaxProtection Replica sincrona, il primario si ferma se lo standby non conferma Zero garantito ","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/data-guard/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eData Guard\u003c/strong\u003e è la tecnologia Oracle che mantiene una o più copie sincronizzate (standby) di un database di produzione (primario). Lo standby riceve e applica continuamente i redo log generati dal primario, rimanendo allineato in tempo reale o quasi.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl primario genera redo log con ogni transazione. Questi log vengono trasmessi allo standby via rete, dove vengono applicati in due modi possibili:\u003c/p\u003e","title":"Data Guard"},{"content":"Un Data Warehouse (DWH) è un sistema di archiviazione dati progettato specificamente per l\u0026rsquo;analisi, il reporting e il supporto alle decisioni aziendali. A differenza dei database operazionali (OLTP), un DWH raccoglie dati da molteplici fonti, li trasforma e li organizza in strutture ottimizzate per le interrogazioni analitiche.\nCome funziona #I dati vengono estratti dai sistemi sorgente (gestionali, CRM, ERP), trasformati attraverso processi ETL che li puliscono, normalizzano e arricchiscono, e infine caricati nel DWH. Il modello dati tipico è lo star schema: una fact table centrale con le misure numeriche collegata a tabelle dimensionali che descrivono il contesto (tempo, cliente, prodotto, geografia).\nA cosa serve #Un DWH permette di rispondere a domande di business che i sistemi operazionali non possono gestire: trend storici, analisi comparative tra periodi, aggregazioni cross-system, KPI aziendali. Separa il carico analitico da quello transazionale, evitando che le query di reporting impattino le performance delle applicazioni operative.\nQuando si usa #Un DWH è necessario quando un\u0026rsquo;azienda ha bisogno di integrare dati da fonti diverse per produrre analisi consolidate. La complessità e i costi dipendono dal numero di sistemi sorgente, dal volume dei dati e dalla frequenza di aggiornamento richiesta.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/data-warehouse/","section":"Glossario","summary":"\u003cp\u003eUn \u003cstrong\u003eData Warehouse\u003c/strong\u003e (DWH) è un sistema di archiviazione dati progettato specificamente per l\u0026rsquo;analisi, il reporting e il supporto alle decisioni aziendali. A differenza dei database operazionali (OLTP), un DWH raccoglie dati da molteplici fonti, li trasforma e li organizza in strutture ottimizzate per le interrogazioni analitiche.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eI dati vengono estratti dai sistemi sorgente (gestionali, CRM, ERP), trasformati attraverso processi ETL che li puliscono, normalizzano e arricchiscono, e infine caricati nel DWH. Il modello dati tipico è lo star schema: una fact table centrale con le misure numeriche collegata a tabelle dimensionali che descrivono il contesto (tempo, cliente, prodotto, geografia).\u003c/p\u003e","title":"Data Warehouse"},{"content":"Un Dead Tuple è una riga in una tabella PostgreSQL che è stata aggiornata (UPDATE) o cancellata (DELETE) ma non è ancora stata rimossa fisicamente. Resta nelle pagine dati, occupando spazio su disco e rallentando le scansioni.\nCome funziona #Quando PostgreSQL esegue un UPDATE, non sovrascrive la riga originale: crea una nuova versione e marca la vecchia come \u0026ldquo;morta\u0026rdquo;. La vecchia riga resta fisicamente nella pagina dati finché il VACUUM non la pulisce. I dead tuples sono il prezzo del modello MVCC — necessari per garantire l\u0026rsquo;isolamento transazionale.\nA cosa serve #I dead tuples sono un indicatore chiave della salute di una tabella. La vista pg_stat_user_tables mostra n_dead_tup e last_autovacuum — se i dead tuples crescono più velocemente di quanto l\u0026rsquo;autovacuum riesca a pulire, la tabella ha un problema. Un dead_tuple_percent sopra il 20-30% è un segnale di allarme.\nCosa può andare storto #Su una tabella con 500.000 update al giorno e il default di autovacuum (scale_factor 0.2), il VACUUM si attiva ogni 4 giorni. Nel frattempo i dead tuples si accumulano, le tabelle si gonfiano e le query rallentano progressivamente — il pattern \u0026ldquo;lunedì bene, venerdì disastro\u0026rdquo;.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/dead-tuple/","section":"Glossario","summary":"\u003cp\u003eUn \u003cstrong\u003eDead Tuple\u003c/strong\u003e è una riga in una tabella PostgreSQL che è stata aggiornata (UPDATE) o cancellata (DELETE) ma non è ancora stata rimossa fisicamente. Resta nelle pagine dati, occupando spazio su disco e rallentando le scansioni.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando PostgreSQL esegue un UPDATE, non sovrascrive la riga originale: crea una nuova versione e marca la vecchia come \u0026ldquo;morta\u0026rdquo;. La vecchia riga resta fisicamente nella pagina dati finché il VACUUM non la pulisce. I dead tuples sono il prezzo del modello MVCC — necessari per garantire l\u0026rsquo;isolamento transazionale.\u003c/p\u003e","title":"Dead Tuple"},{"content":"DEFAULT PRIVILEGES è un meccanismo PostgreSQL che permette di definire in anticipo i privilegi che verranno assegnati automaticamente a tutti gli oggetti futuri creati in uno schema. Si configura con il comando ALTER DEFAULT PRIVILEGES.\nCome funziona #Il comando ALTER DEFAULT PRIVILEGES IN SCHEMA schema1 GRANT SELECT ON TABLES TO srv_monitoraggio fa sì che ogni nuova tabella creata in schema1 sia automaticamente leggibile da srv_monitoraggio. Senza questa configurazione, le tabelle future richiederebbero un GRANT manuale ogni volta.\nA cosa serve #È la parte che la maggior parte degli amministratori dimentica quando crea utenti read-only. I GRANT su ALL TABLES IN SCHEMA coprono solo le tabelle esistenti. Le tabelle create dopo richiedono nuovi GRANT — a meno che non si usino i DEFAULT PRIVILEGES. Senza di essi, l\u0026rsquo;utente di monitoraggio smette di funzionare alla prima nuova tabella.\nCosa può andare storto #I DEFAULT PRIVILEGES valgono per il ROLE che crea gli oggetti. Se in uno schema più utenti creano tabelle, i default privileges vanno configurati per ciascun creatore. Questo dettaglio causa spesso errori difficili da diagnosticare: \u0026ldquo;il GRANT c\u0026rsquo;è, ma la nuova tabella non è leggibile.\u0026rdquo;\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/default-privileges/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eDEFAULT PRIVILEGES\u003c/strong\u003e è un meccanismo PostgreSQL che permette di definire in anticipo i privilegi che verranno assegnati automaticamente a tutti gli oggetti futuri creati in uno schema. Si configura con il comando \u003ccode\u003eALTER DEFAULT PRIVILEGES\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl comando \u003ccode\u003eALTER DEFAULT PRIVILEGES IN SCHEMA schema1 GRANT SELECT ON TABLES TO srv_monitoraggio\u003c/code\u003e fa sì che ogni nuova tabella creata in \u003ccode\u003eschema1\u003c/code\u003e sia automaticamente leggibile da \u003ccode\u003esrv_monitoraggio\u003c/code\u003e. Senza questa configurazione, le tabelle future richiederebbero un GRANT manuale ogni volta.\u003c/p\u003e","title":"DEFAULT PRIVILEGES"},{"content":"default_statistics_target è il parametro PostgreSQL che definisce il numero di campioni raccolti dal comando ANALYZE per costruire le statistiche di ogni colonna. Il valore di default è 100.\nCome funziona #PostgreSQL campiona un certo numero di valori per ogni colonna e li usa per costruire due strutture:\nMost common values (MCV): la lista dei valori più frequenti, con le rispettive frequenze Istogramma: la distribuzione dei valori rimanenti, divisa in bucket di uguale popolazione Il parametro default_statistics_target determina quanti elementi avranno queste strutture. Con il valore 100 (default), l\u0026rsquo;istogramma avrà 100 bucket e la lista MCV conterrà fino a 100 valori.\nQuando aumentarlo #Per tabelle piccole o con distribuzione uniforme, 100 campioni sono sufficienti. Per tabelle grandi con distribuzione asimmetrica (skewed) — dove pochi valori dominano la maggior parte delle righe — 100 campioni possono dare una rappresentazione distorta, portando l\u0026rsquo;optimizer a stime di cardinalità sbagliate.\nSi può aumentare il target a livello di singola colonna:\nALTER TABLE orders ALTER COLUMN status SET STATISTICS 500; ANALYZE orders; Valori tra 500 e 1000 migliorano sensibilmente la qualità delle stime su colonne con distribuzione non uniforme.\nLimiti pratici #Oltre 1000 il beneficio è marginale e l\u0026rsquo;ANALYZE stesso diventa più lento, perché deve campionare più righe e costruire strutture più grandi. È una regolazione fine: va applicata solo alle colonne che effettivamente causano stime errate, non a tutte le colonne di tutte le tabelle.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/postgresql-default-statistics-target/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003edefault_statistics_target\u003c/strong\u003e è il parametro PostgreSQL che definisce il numero di campioni raccolti dal comando \u003ccode\u003eANALYZE\u003c/code\u003e per costruire le statistiche di ogni colonna. Il valore di default è 100.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003ePostgreSQL campiona un certo numero di valori per ogni colonna e li usa per costruire due strutture:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eMost common values (MCV)\u003c/strong\u003e: la lista dei valori più frequenti, con le rispettive frequenze\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eIstogramma\u003c/strong\u003e: la distribuzione dei valori rimanenti, divisa in bucket di uguale popolazione\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIl parametro \u003ccode\u003edefault_statistics_target\u003c/code\u003e determina quanti elementi avranno queste strutture. Con il valore 100 (default), l\u0026rsquo;istogramma avrà 100 bucket e la lista MCV conterrà fino a 100 valori.\u003c/p\u003e","title":"default_statistics_target"},{"content":"La Direttiva 2011/7/UE è la normativa europea sui ritardi di pagamento nelle transazioni commerciali. Stabilisce regole chiare: termine standard di 30 giorni, massimo 60 tra imprese (con accordo esplicito), 30 per la PA, e interessi di mora automatici al tasso BCE + 8%.\nCome funziona #La direttiva è stata recepita in Italia con il D.Lgs. 231/2002 (modificato nel 2012). Sulla carta le regole ci sono: 30 giorni standard, interessi automatici, compenso forfettario di 40€ per fattura pagata in ritardo. Nella pratica italiana è come se non esistessero — il DSO medio italiano è 80 giorni, ben oltre il massimo di 60.\nA cosa serve #Dovrebbe proteggere i fornitori — in particolare le piccole imprese e i freelance — dai ritardi di pagamento strutturali. In paesi come Germania (DSO 24 giorni) e Paesi Bassi (DSO 27 giorni) la direttiva funziona. In Italia il gap tra norma e realtà è abissale.\nPerché è critico #La direttiva dimostra che il problema dei ritardi di pagamento in Italia non è legislativo — le leggi ci sono. È culturale e strutturale: il costo reputazionale di far valere i propri diritti supera il beneficio economico, e il sistema si regge sulla docilità del creditore.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/direttiva-2011-7-ue/","section":"Glossario","summary":"\u003cp\u003eLa \u003cstrong\u003eDirettiva 2011/7/UE\u003c/strong\u003e è la normativa europea sui ritardi di pagamento nelle transazioni commerciali. Stabilisce regole chiare: termine standard di 30 giorni, massimo 60 tra imprese (con accordo esplicito), 30 per la PA, e interessi di mora automatici al tasso BCE + 8%.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa direttiva è stata recepita in Italia con il D.Lgs. 231/2002 (modificato nel 2012). Sulla carta le regole ci sono: 30 giorni standard, interessi automatici, compenso forfettario di 40€ per fattura pagata in ritardo. Nella pratica italiana è come se non esistessero — il DSO medio italiano è 80 giorni, ben oltre il massimo di 60.\u003c/p\u003e","title":"Direttiva 2011/7/UE"},{"content":"Il drill-down è l\u0026rsquo;operazione di navigazione nei report che permette di passare da un livello aggregato a un livello di maggiore dettaglio, scendendo lungo una gerarchia.\nCome funziona #In una gerarchia Top Group → Group → Client:\nSi parte dal livello più alto: fatturato totale per Top Group Si clicca su un Top Group per vedere i suoi Group (drill-down di primo livello) Si clicca su un Group per vedere i singoli Client (drill-down di secondo livello) L\u0026rsquo;operazione inversa — risalire dal dettaglio all\u0026rsquo;aggregato — si chiama drill-up (o roll-up).\nRequisiti per un drill-down corretto #Per funzionare senza errori, il drill-down richiede:\nUna gerarchia completa: nessun livello mancante (niente NULL) Coerenza dei totali: la somma dei valori al livello di dettaglio deve corrispondere al totale del livello superiore Struttura bilanciata: tutti i rami della gerarchia devono avere la stessa profondità Se la gerarchia è sbilanciata (ragged hierarchy), il drill-down produce risultati incompleti o errati. Il self-parenting risolve questo problema bilanciando la struttura a monte.\nDrill-down vs filtro #Il drill-down non è un semplice filtro: è una navigazione strutturata lungo una gerarchia predefinita. Un filtro mostra un sottoinsieme dei dati; un drill-down mostra il livello successivo di dettaglio all\u0026rsquo;interno di un contesto gerarchico.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/drill-down/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003edrill-down\u003c/strong\u003e è l\u0026rsquo;operazione di navigazione nei report che permette di passare da un livello aggregato a un livello di maggiore dettaglio, scendendo lungo una gerarchia.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIn una gerarchia Top Group → Group → Client:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eSi parte dal livello più alto: fatturato totale per Top Group\u003c/li\u003e\n\u003cli\u003eSi clicca su un Top Group per vedere i suoi Group (drill-down di primo livello)\u003c/li\u003e\n\u003cli\u003eSi clicca su un Group per vedere i singoli Client (drill-down di secondo livello)\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eL\u0026rsquo;operazione inversa — risalire dal dettaglio all\u0026rsquo;aggregato — si chiama \u003cstrong\u003edrill-up\u003c/strong\u003e (o roll-up).\u003c/p\u003e","title":"Drill-down"},{"content":"Il DSO (Days Sales Outstanding) è la metrica che misura il numero medio di giorni che un\u0026rsquo;azienda impiega per incassare i propri crediti dopo l\u0026rsquo;emissione della fattura. È l\u0026rsquo;indicatore principale della velocità di pagamento in un mercato.\nCome funziona #Si calcola come: (Crediti commerciali / Fatturato) × Giorni del periodo. Un DSO di 30 significa che in media i clienti pagano entro un mese. In Italia il DSO medio è di 80 giorni secondo l\u0026rsquo;European Payment Report — quasi tre volte la media del nord Europa (24-27 giorni).\nA cosa serve #Per un consulente freelance, il DSO determina il fabbisogno di capitale circolante. Con un DSO di 90 giorni e un fatturato di 5.500€/mese, servono almeno 16.500€ di riserva per coprire i primi tre mesi senza incassi. Senza riserva, il consulente sta finanziando il proprio cliente a costo zero.\nPerché è critico #L\u0026rsquo;Italia è fuori scala rispetto alla Direttiva UE che fissa il termine massimo a 60 giorni. Un DSO di 80 giorni non è solo un problema finanziario — è un indicatore strutturale di un mercato dove il potere contrattuale è sbilanciato a favore del committente.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/dso/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eDSO\u003c/strong\u003e (Days Sales Outstanding) è la metrica che misura il numero medio di giorni che un\u0026rsquo;azienda impiega per incassare i propri crediti dopo l\u0026rsquo;emissione della fattura. È l\u0026rsquo;indicatore principale della velocità di pagamento in un mercato.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSi calcola come: \u003ccode\u003e(Crediti commerciali / Fatturato) × Giorni del periodo\u003c/code\u003e. Un DSO di 30 significa che in media i clienti pagano entro un mese. In Italia il DSO medio è di 80 giorni secondo l\u0026rsquo;European Payment Report — quasi tre volte la media del nord Europa (24-27 giorni).\u003c/p\u003e","title":"DSO"},{"content":"ETL (Extract, Transform, Load) è il processo fondamentale attraverso cui i dati vengono spostati dai sistemi sorgente (database operazionali, file, API) al data warehouse.\nLe tre fasi # Extract: estrazione dei dati dai sistemi sorgente. Può essere completa (full load) o incrementale (solo i dati nuovi o modificati) Transform: pulizia, validazione, standardizzazione e arricchimento dei dati. Qui si applicano le regole di business, le lookup sulle dimensioni, i calcoli derivati Load: caricamento dei dati trasformati nelle tabelle del data warehouse (fact e dimension) Perché è critico #L\u0026rsquo;ETL è la parte meno visibile ma più critica di un data warehouse. Se i dati vengono estratti in modo incompleto, trasformati con regole errate o caricati senza controlli, tutto ciò che sta sopra — report, dashboard, decisioni — sarà sbagliato.\nUn ETL ben progettato è anche quello che determina la finestra di caricamento: quanto tempo serve per aggiornare il data warehouse. In ambienti reali, passare da 4 ore a 25 minuti può fare la differenza tra dati aggiornati alla mattina o al pomeriggio.\nELT vs ETL #Con l\u0026rsquo;avvento dei data warehouse cloud e dei motori colonnari ad alte performance, si è diffuso il pattern ELT (Extract, Load, Transform): i dati vengono caricati grezzi nel warehouse e trasformati direttamente lì, sfruttando la potenza di calcolo del motore SQL. Il concetto di fondo resta lo stesso, cambia dove avviene la trasformazione.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/etl/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eETL\u003c/strong\u003e (Extract, Transform, Load) è il processo fondamentale attraverso cui i dati vengono spostati dai sistemi sorgente (database operazionali, file, API) al data warehouse.\u003c/p\u003e\n\u003ch2 id=\"le-tre-fasi\" class=\"relative group\"\u003eLe tre fasi \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#le-tre-fasi\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eExtract\u003c/strong\u003e: estrazione dei dati dai sistemi sorgente. Può essere completa (full load) o incrementale (solo i dati nuovi o modificati)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTransform\u003c/strong\u003e: pulizia, validazione, standardizzazione e arricchimento dei dati. Qui si applicano le regole di business, le lookup sulle dimensioni, i calcoli derivati\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLoad\u003c/strong\u003e: caricamento dei dati trasformati nelle tabelle del data warehouse (fact e dimension)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"perché-è-critico\" class=\"relative group\"\u003ePerché è critico \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#perch%c3%a9-%c3%a8-critico\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eL\u0026rsquo;ETL è la parte meno visibile ma più critica di un data warehouse. Se i dati vengono estratti in modo incompleto, trasformati con regole errate o caricati senza controlli, tutto ciò che sta sopra — report, dashboard, decisioni — sarà sbagliato.\u003c/p\u003e","title":"ETL"},{"content":"L\u0026rsquo;Exchange Partition è un\u0026rsquo;operazione DDL di Oracle che permette di scambiare istantaneamente il contenuto di una partizione con quello di una tabella non partizionata. Non viene spostato nemmeno un byte di dati — l\u0026rsquo;operazione modifica solo i puntatori nel data dictionary.\nCome funziona #Il comando ALTER TABLE ... EXCHANGE PARTITION ... WITH TABLE ... modifica i metadati nel data dictionary in modo che i segmenti fisici della partizione e della tabella di staging si scambino. La tabella di staging diventa la partizione e viceversa. L\u0026rsquo;operazione dura meno di un secondo indipendentemente dal volume dei dati, perché non implica alcun movimento fisico.\nA cosa serve #Nei data warehouse, l\u0026rsquo;exchange partition è lo strumento principale per il caricamento bulk dei dati. Il processo tipico è: l\u0026rsquo;ETL carica i dati in una tabella di staging, costruisce gli indici, valida i dati, e poi esegue l\u0026rsquo;exchange con la partizione target. Durante l\u0026rsquo;exchange, le query sulle altre partizioni continuano a funzionare senza interruzione.\nCosa può andare storto #La clausola WITHOUT VALIDATION salta il controllo che i dati della staging table rientrino effettivamente nell\u0026rsquo;intervallo della partizione — velocizza l\u0026rsquo;operazione ma richiede che l\u0026rsquo;ETL garantisca la correttezza dei dati. Se i dati nella staging contengono date fuori intervallo, finiscono nella partizione sbagliata senza alcun errore. La clausola INCLUDING INDEXES richiede che la staging table abbia indici con la stessa struttura degli indici locali della tabella partizionata.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/exchange-partition/","section":"Glossario","summary":"\u003cp\u003eL\u0026rsquo;\u003cstrong\u003eExchange Partition\u003c/strong\u003e è un\u0026rsquo;operazione DDL di Oracle che permette di scambiare istantaneamente il contenuto di una partizione con quello di una tabella non partizionata. Non viene spostato nemmeno un byte di dati — l\u0026rsquo;operazione modifica solo i puntatori nel data dictionary.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl comando \u003ccode\u003eALTER TABLE ... EXCHANGE PARTITION ... WITH TABLE ...\u003c/code\u003e modifica i metadati nel data dictionary in modo che i segmenti fisici della partizione e della tabella di staging si scambino. La tabella di staging diventa la partizione e viceversa. L\u0026rsquo;operazione dura meno di un secondo indipendentemente dal volume dei dati, perché non implica alcun movimento fisico.\u003c/p\u003e","title":"Exchange Partition"},{"content":"Execution plan (piano di esecuzione) è la sequenza di operazioni che il database sceglie per risolvere una query SQL. Quando scrivi una SELECT con JOIN, filtri WHERE e ordinamenti, l\u0026rsquo;optimizer valuta decine di strategie possibili e ne sceglie una basandosi sulle statistiche disponibili.\nCome funziona #Il piano è rappresentato come un albero di nodi: ogni nodo è un\u0026rsquo;operazione (scan, join, sort, aggregate) che riceve dati dai nodi figli e li passa al nodo padre. In PostgreSQL si visualizza con EXPLAIN (piano stimato) o EXPLAIN ANALYZE (piano reale con tempi effettivi e conteggi righe).\nL\u0026rsquo;optimizer decide per ogni nodo quale strategia usare: sequential scan o index scan per l\u0026rsquo;accesso alle tabelle, nested loop, hash join o merge join per le giunzioni, sort o hash per i raggruppamenti.\nPerché è importante #La lettura corretta di un piano di esecuzione è la competenza più importante per il tuning delle query. Non basta guardare il tempo totale: bisogna confrontare le righe stimate con quelle reali nodo per nodo, verificare i buffer I/O e identificare dove l\u0026rsquo;optimizer ha fatto scelte sbagliate.\nUna stima errata anche di un solo nodo può propagarsi a cascata su tutto il piano, trasformando una query da millisecondi a minuti.\nCosa può andare storto #I problemi più frequenti nei piani di esecuzione:\nStime di cardinalità sbagliate: l\u0026rsquo;optimizer pensa che una tabella restituisca 100 righe e ne arrivano 2 milioni Join sbagliato: un nested loop scelto dove serviva un hash join, a causa di statistiche obsolete Indice ignorato: un sequential scan su una tabella grande perché le statistiche non riflettono la distribuzione reale dei dati Spill su disco: operazioni di sort o hash che non stanno in work_mem e finiscono su disco ","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/execution-plan/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eExecution plan\u003c/strong\u003e (piano di esecuzione) è la sequenza di operazioni che il database sceglie per risolvere una query SQL. Quando scrivi una SELECT con JOIN, filtri WHERE e ordinamenti, l\u0026rsquo;optimizer valuta decine di strategie possibili e ne sceglie una basandosi sulle statistiche disponibili.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl piano è rappresentato come un albero di nodi: ogni nodo è un\u0026rsquo;operazione (scan, join, sort, aggregate) che riceve dati dai nodi figli e li passa al nodo padre. In PostgreSQL si visualizza con \u003ccode\u003eEXPLAIN\u003c/code\u003e (piano stimato) o \u003ccode\u003eEXPLAIN ANALYZE\u003c/code\u003e (piano reale con tempi effettivi e conteggi righe).\u003c/p\u003e","title":"Execution Plan"},{"content":"Il Facilitatore è la persona incaricata di guidare lo svolgimento di una riunione. Non è chi decide — è chi garantisce che la decisione venga presa in modo ordinato, nei tempi previsti e con il contributo di tutti i partecipanti.\nCome funziona #Il facilitatore tiene il tempo, gestisce i turni di parola, taglia le discussioni fuori tema (\u0026ldquo;lo segno nel parking lot, ne parliamo dopo\u0026rdquo;) e si assicura che lo standup non superi i 15 minuti. Il ruolo può essere fisso o a rotazione nel team.\nA cosa serve #Senza facilitatore, le riunioni si espandono naturalmente. Qualcuno prende la parola più del dovuto, qualcun altro non parla mai, e gli argomenti si moltiplicano senza controllo. Il facilitatore è il guardiano del tempo di tutti — non è autoritario, è rispettoso.\nPerché è critico #Il facilitatore migliore è quello che taglia con naturalezza: \u0026ldquo;Interessante, ne parliamo subito dopo. Marco, tocca a te.\u0026rdquo; Senza questa figura, lo standup degenera nel giro di tre settimane. La differenza tra uno standup da 15 minuti e uno da 45 è quasi sempre la presenza (o assenza) di un facilitatore con la spina dorsale.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/facilitatore/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eFacilitatore\u003c/strong\u003e è la persona incaricata di guidare lo svolgimento di una riunione. Non è chi decide — è chi garantisce che la decisione venga presa in modo ordinato, nei tempi previsti e con il contributo di tutti i partecipanti.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl facilitatore tiene il tempo, gestisce i turni di parola, taglia le discussioni fuori tema (\u0026ldquo;lo segno nel parking lot, ne parliamo dopo\u0026rdquo;) e si assicura che lo standup non superi i 15 minuti. Il ruolo può essere fisso o a rotazione nel team.\u003c/p\u003e","title":"Facilitatore"},{"content":"La fact table (tabella dei fatti) è la tabella centrale di uno star schema nel data warehouse. Contiene le misure numeriche — importi, quantità, conteggi, durate — e le chiavi esterne che la collegano alle tabelle dimensionali.\nStruttura #Ogni riga della fact table rappresenta un evento o una transazione di business: una vendita, un sinistro, una spedizione, un accesso. Le colonne si dividono in due categorie:\nChiavi esterne (foreign key): puntano alle tabelle dimensionali (chi, cosa, dove, quando) Misure: i valori numerici da aggregare (importo, quantità, margine) Tipi di fact table # Transaction fact: una riga per ogni evento (es. ogni vendita) Periodic snapshot: una riga per periodo per entità (es. saldo mensile per conto) Accumulating snapshot: una riga per processo, aggiornata a ogni milestone (es. ciclo ordine-spedizione-fatturazione) Relazione con le SCD #Quando le dimensioni usano SCD Tipo 2, la fact table punta alla chiave surrogata della dimensione — non alla chiave naturale. Questo garantisce che ogni fatto sia associato alla versione della dimensione corretta per il momento in cui è accaduto.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/fact-table/","section":"Glossario","summary":"\u003cp\u003eLa \u003cstrong\u003efact table\u003c/strong\u003e (tabella dei fatti) è la tabella centrale di uno star schema nel data warehouse. Contiene le misure numeriche — importi, quantità, conteggi, durate — e le chiavi esterne che la collegano alle tabelle dimensionali.\u003c/p\u003e\n\u003ch2 id=\"struttura\" class=\"relative group\"\u003eStruttura \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#struttura\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOgni riga della fact table rappresenta un evento o una transazione di business: una vendita, un sinistro, una spedizione, un accesso. Le colonne si dividono in due categorie:\u003c/p\u003e","title":"Fact table"},{"content":"Il Float Finanziario è la liquidità che un\u0026rsquo;azienda genera dalla differenza tra i tempi di incasso dai propri clienti (più brevi) e i tempi di pagamento ai propri fornitori (più lunghi). È di fatto un prestito a costo zero ottenuto a spese dei fornitori.\nCome funziona #Una società di consulenza incassa dal cliente finale a 30 giorni ma paga i propri consulenti a 90 giorni. La differenza di 60 giorni genera un float: per ogni 100.000€ di fatturato mensile, l\u0026rsquo;azienda dispone di ~200.000€ di liquidità gratuita che può investire o usare come capitale circolante.\nA cosa serve #Per le grandi aziende è una leva finanziaria strutturale. Per i consulenti freelance è il meccanismo perverso per cui si trovano a finanziare i propri clienti senza interessi, senza garanzie e senza alternativa — perché il mercato \u0026ldquo;funziona così.\u0026rdquo;\nPerché è critico #Il float finanziario è un trasferimento di ricchezza invisibile dal fornitore al committente. Il consulente che lavora a ottobre e incassa a febbraio sta erogando un prestito di quattro mesi. Nessuno lo chiama così — lo chiamano \u0026ldquo;termini contrattuali.\u0026rdquo; Ma economicamente è identico.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/float-finanziario/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eFloat Finanziario\u003c/strong\u003e è la liquidità che un\u0026rsquo;azienda genera dalla differenza tra i tempi di incasso dai propri clienti (più brevi) e i tempi di pagamento ai propri fornitori (più lunghi). È di fatto un prestito a costo zero ottenuto a spese dei fornitori.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUna società di consulenza incassa dal cliente finale a 30 giorni ma paga i propri consulenti a 90 giorni. La differenza di 60 giorni genera un float: per ogni 100.000€ di fatturato mensile, l\u0026rsquo;azienda dispone di ~200.000€ di liquidità gratuita che può investire o usare come capitale circolante.\u003c/p\u003e","title":"Float Finanziario"},{"content":"FLUSH PRIVILEGES è un comando MySQL/MariaDB che forza il server a ricaricare in memoria le tabelle dei privilegi dal database mysql. Rende immediatamente effettive le modifiche ai permessi.\nCome funziona #MySQL mantiene in memoria una cache delle tabelle dei grant (mysql.user, mysql.db, mysql.tables_priv). Quando si usano CREATE USER e GRANT, MySQL aggiorna sia le tabelle che la cache automaticamente. Ma se si modificano le tabelle dei grant direttamente con INSERT, UPDATE o DELETE, la cache non viene aggiornata. FLUSH PRIVILEGES forza il reload della cache dalle tabelle.\nA cosa serve #Il comando è necessario dopo: eliminazione diretta di utenti dalla tabella mysql.user, modifiche manuali ai privilegi via DML, o dopo un DROP USER di utenti anonimi come parte dell\u0026rsquo;hardening di sicurezza. Senza il FLUSH, le modifiche non hanno effetto fino al prossimo riavvio del server.\nQuando si usa #Dopo qualsiasi modifica diretta alle tabelle dei grant. Se si usano esclusivamente CREATE USER, GRANT, REVOKE e DROP USER, il FLUSH non è tecnicamente necessario perché questi comandi aggiornano la cache automaticamente. Tuttavia, eseguirlo dopo un DROP USER di utenti anonimi è una buona pratica per garantire la consistenza.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/flush-privileges/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eFLUSH PRIVILEGES\u003c/strong\u003e è un comando MySQL/MariaDB che forza il server a ricaricare in memoria le tabelle dei privilegi dal database \u003ccode\u003emysql\u003c/code\u003e. Rende immediatamente effettive le modifiche ai permessi.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eMySQL mantiene in memoria una cache delle tabelle dei grant (\u003ccode\u003emysql.user\u003c/code\u003e, \u003ccode\u003emysql.db\u003c/code\u003e, \u003ccode\u003emysql.tables_priv\u003c/code\u003e). Quando si usano \u003ccode\u003eCREATE USER\u003c/code\u003e e \u003ccode\u003eGRANT\u003c/code\u003e, MySQL aggiorna sia le tabelle che la cache automaticamente. Ma se si modificano le tabelle dei grant direttamente con \u003ccode\u003eINSERT\u003c/code\u003e, \u003ccode\u003eUPDATE\u003c/code\u003e o \u003ccode\u003eDELETE\u003c/code\u003e, la cache non viene aggiornata. \u003ccode\u003eFLUSH PRIVILEGES\u003c/code\u003e forza il reload della cache dalle tabelle.\u003c/p\u003e","title":"FLUSH PRIVILEGES"},{"content":"Full Table Scan (o TABLE ACCESS FULL) è un\u0026rsquo;operazione in cui il database legge tutti i blocchi dati di una tabella, dall\u0026rsquo;inizio alla fine, senza passare per alcun indice.\nCome funziona #Oracle richiede blocchi dal disco (o dalla cache) in sequenza, usando letture multi-blocco (db file scattered read). Ogni riga della tabella viene esaminata, indipendentemente dal fatto che soddisfi o meno i criteri della query.\nQuando è un problema #Un full table scan su una tabella grande è spesso il segno di un indice mancante, di statistiche obsolete o di un piano di esecuzione cambiato. Nel report AWR compare come db file scattered read nella sezione Top Wait Events, con percentuali elevate di DB time.\nQuando è legittimo #Su tabelle piccole (poche migliaia di righe) o quando la query deve effettivamente leggere la maggior parte dei dati, il full table scan può essere più efficiente di un accesso via indice. Il problema nasce quando Oracle lo sceglie su tabelle con milioni di righe per estrarre pochi record.\nCome si identifica #Nel piano di esecuzione (EXPLAIN PLAN o DBMS_XPLAN) compare come operazione TABLE ACCESS FULL. Nei wait event di AWR/ASH si manifesta come db file scattered read dominante.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/full-table-scan/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eFull Table Scan\u003c/strong\u003e (o TABLE ACCESS FULL) è un\u0026rsquo;operazione in cui il database legge tutti i blocchi dati di una tabella, dall\u0026rsquo;inizio alla fine, senza passare per alcun indice.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOracle richiede blocchi dal disco (o dalla cache) in sequenza, usando letture multi-blocco (\u003ccode\u003edb file scattered read\u003c/code\u003e). Ogni riga della tabella viene esaminata, indipendentemente dal fatto che soddisfi o meno i criteri della query.\u003c/p\u003e","title":"Full Table Scan"},{"content":"Un GIN Index (Generalized Inverted Index) è un tipo di indice PostgreSQL progettato per indicizzare valori composti: array, documenti JSONB, testo con trigrammi e ricerche full-text. A differenza del B-Tree, un GIN crea un mapping inverso: da ogni elemento (parola, trigramma, chiave JSON) ai record che lo contengono.\nCome funziona #Per ogni valore distinto nel dato indicizzato, il GIN mantiene una lista di puntatori alle righe che contengono quel valore. Nel caso di pg_trgm, il testo viene scomposto in trigrammi (sequenze di 3 caratteri) e ogni trigramma viene indicizzato. Una ricerca LIKE '%ABC%' viene tradotta in un\u0026rsquo;intersezione di trigrammi, evitando la scansione sequenziale.\nA cosa serve #GIN risolve il problema delle ricerche \u0026ldquo;contiene\u0026rdquo; (LIKE '%valore%') su colonne di testo, che con un B-Tree richiederebbero una scansione sequenziale dell\u0026rsquo;intera tabella. Su tabelle di milioni di righe, la differenza è tra secondi e millisecondi.\nQuando si usa #GIN è ideale su tabelle append-only o con basso churn (pochi UPDATE/DELETE), perché il costo di manutenzione dell\u0026rsquo;indice è più alto rispetto a un B-Tree. La creazione in produzione va fatta con CREATE INDEX CONCURRENTLY per evitare lock sulle scritture.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/gin-index/","section":"Glossario","summary":"\u003cp\u003eUn \u003cstrong\u003eGIN Index\u003c/strong\u003e (Generalized Inverted Index) è un tipo di indice PostgreSQL progettato per indicizzare valori composti: array, documenti JSONB, testo con trigrammi e ricerche full-text. A differenza del B-Tree, un GIN crea un mapping inverso: da ogni elemento (parola, trigramma, chiave JSON) ai record che lo contengono.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003ePer ogni valore distinto nel dato indicizzato, il GIN mantiene una lista di puntatori alle righe che contengono quel valore. Nel caso di \u003ccode\u003epg_trgm\u003c/code\u003e, il testo viene scomposto in trigrammi (sequenze di 3 caratteri) e ogni trigramma viene indicizzato. Una ricerca \u003ccode\u003eLIKE '%ABC%'\u003c/code\u003e viene tradotta in un\u0026rsquo;intersezione di trigrammi, evitando la scansione sequenziale.\u003c/p\u003e","title":"GIN Index"},{"content":"","date":null,"permalink":"https://ivanluminaria.com/it/glossary/","section":"Glossario","summary":"","title":"Glossario"},{"content":"Il grain (grana, granularità) è il livello di dettaglio di una fact table nel data warehouse. Definisce cosa rappresenta una singola riga: una transazione, un riepilogo giornaliero, un totale mensile, una riga di fattura.\nCome funziona #La scelta del grain è la prima decisione nella progettazione di una fact table. Ogni altra scelta — misure, dimensioni, ETL — discende da essa:\nGrain fine (es. riga di fattura): massima flessibilità nelle query, più righe da gestire Grain aggregato (es. totale mensile per cliente): meno righe, query più veloci, ma impossibilità di scendere nel dettaglio Il principio fondamentale di Kimball: modellare sempre al livello di dettaglio più fine disponibile nel sistema sorgente.\nA cosa serve #Il grain determina:\nQuali domande il data warehouse può soddisfare Quali dimensioni servono (un grain per riga di fattura richiede dim_prodotto, un grain mensile no) Quanto è grande la fact table e quanto dura l\u0026rsquo;ETL Se il drill-down nei report è possibile oppure no Quando si usa #Il grain si definisce nella fase di progettazione del modello dimensionale, prima di scrivere qualsiasi DDL o ETL. Cambiare il grain dopo il go-live equivale a ricostruire il data warehouse da zero — motivo per cui la scelta iniziale è così critica.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/grain/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003egrain\u003c/strong\u003e (grana, granularità) è il livello di dettaglio di una fact table nel data warehouse. Definisce cosa rappresenta una singola riga: una transazione, un riepilogo giornaliero, un totale mensile, una riga di fattura.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa scelta del grain è la prima decisione nella progettazione di una fact table. Ogni altra scelta — misure, dimensioni, ETL — discende da essa:\u003c/p\u003e","title":"Grain"},{"content":"GRANT è il comando SQL usato per assegnare privilegi a un utente o ruolo su oggetti specifici del database. In MySQL e MariaDB, i privilegi vengono assegnati alla coppia 'utente'@'host', non solo al nome utente.\nCome funziona #La sintassi base è GRANT \u0026lt;privilegi\u0026gt; ON \u0026lt;database\u0026gt;.\u0026lt;tabella\u0026gt; TO 'utente'@'host'. I privilegi possono essere granulari (SELECT, INSERT, UPDATE, DELETE) o globali (ALL PRIVILEGES). In MySQL 8, GRANT non crea più utenti implicitamente: serve prima un CREATE USER esplicito, poi il GRANT. In MySQL 5.7 e MariaDB, GRANT con IDENTIFIED BY crea l\u0026rsquo;utente e assegna i privilegi in un solo comando.\nA cosa serve #GRANT è il meccanismo fondamentale per implementare il controllo degli accessi nei database MySQL/MariaDB. Combinato con il modello utente@host, permette di calibrare i privilegi in base all\u0026rsquo;origine della connessione: accesso completo da localhost per il DBA, solo lettura dall\u0026rsquo;application server.\nQuando si usa #Ogni volta che si crea un utente o si modificano i permessi. La best practice è assegnare sempre il minimo privilegio necessario (principio del least privilege) e usare SHOW GRANTS FOR 'utente'@'host' per verificare i privilegi effettivi.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/grant/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eGRANT\u003c/strong\u003e è il comando SQL usato per assegnare privilegi a un utente o ruolo su oggetti specifici del database. In MySQL e MariaDB, i privilegi vengono assegnati alla coppia \u003ccode\u003e'utente'@'host'\u003c/code\u003e, non solo al nome utente.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa sintassi base è \u003ccode\u003eGRANT \u0026lt;privilegi\u0026gt; ON \u0026lt;database\u0026gt;.\u0026lt;tabella\u0026gt; TO 'utente'@'host'\u003c/code\u003e. I privilegi possono essere granulari (SELECT, INSERT, UPDATE, DELETE) o globali (ALL PRIVILEGES). In MySQL 8, GRANT non crea più utenti implicitamente: serve prima un \u003ccode\u003eCREATE USER\u003c/code\u003e esplicito, poi il GRANT. In MySQL 5.7 e MariaDB, GRANT con \u003ccode\u003eIDENTIFIED BY\u003c/code\u003e crea l\u0026rsquo;utente e assegna i privilegi in un solo comando.\u003c/p\u003e","title":"GRANT"},{"content":"Group Replication è il meccanismo nativo di MySQL per creare cluster ad alta disponibilità con replica sincrona tra più nodi. A differenza della replica classica (asincrona, master-slave), Group Replication garantisce che ogni transazione sia confermata dalla maggioranza dei nodi prima di essere considerata committata.\nCome funziona #I nodi comunicano tramite un protocollo di gruppo (GCS — Group Communication System) che gestisce il consenso distribuito. Ogni nodo mantiene una copia completa dei dati. Le transazioni vengono certificate dal gruppo: se non ci sono conflitti, vengono applicate su tutti i nodi. Se c\u0026rsquo;è un conflitto, la transazione viene annullata sul nodo che l\u0026rsquo;ha originata.\nModalità operative #MySQL Group Replication supporta due modalità: single-primary (un solo nodo accetta scritture, gli altri sono in sola lettura) e multi-primary (tutti i nodi accettano scritture). La modalità single-primary è la più usata in produzione perché evita i conflitti di scrittura concorrente.\nPerché è critico #Group Replication gestisce automaticamente il failover: se il primary cade, il cluster elegge un nuovo primary tra i secondary in pochi secondi. Questo lo rende adatto per ambienti che richiedono alta disponibilità senza intervento manuale. Richiede un minimo di tre nodi per mantenere il quorum.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/group-replication/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eGroup Replication\u003c/strong\u003e è il meccanismo nativo di MySQL per creare cluster ad alta disponibilità con replica sincrona tra più nodi. A differenza della replica classica (asincrona, master-slave), Group Replication garantisce che ogni transazione sia confermata dalla maggioranza dei nodi prima di essere considerata committata.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eI nodi comunicano tramite un protocollo di gruppo (GCS — Group Communication System) che gestisce il consenso distribuito. Ogni nodo mantiene una copia completa dei dati. Le transazioni vengono certificate dal gruppo: se non ci sono conflitti, vengono applicate su tutti i nodi. Se c\u0026rsquo;è un conflitto, la transazione viene annullata sul nodo che l\u0026rsquo;ha originata.\u003c/p\u003e","title":"Group Replication"},{"content":"GTID (Global Transaction Identifier) è un identificativo univoco assegnato automaticamente a ogni transazione committata su un server MySQL. Il formato è server_uuid:transaction_id — ad esempio 3E11FA47-71CA-11E1-9E33-C80AA9429562:23.\nCome funziona #Quando il GTID è abilitato (gtid_mode = ON), ogni transazione riceve un identificativo che la rende tracciabile su qualsiasi server del cluster di replica. Lo slave sa esattamente quali transazioni ha già eseguito e quali deve ancora ricevere, senza bisogno di specificare manualmente posizioni di binlog (file + offset).\nIl set di tutti i GTID eseguiti su un server è memorizzato nella variabile gtid_executed. Quando uno slave si connette al master, confronta il proprio gtid_executed con quello del master per determinare quali transazioni mancano.\nA cosa serve #Il GTID semplifica radicalmente la gestione della replica MySQL:\nFailover automatico: quando il master cade, uno slave può diventare il nuovo master e gli altri slave si riallineano automaticamente Verifica della consistenza: è possibile verificare se due server hanno eseguito esattamente le stesse transazioni Backup e restore: strumenti come mysqldump e mydumper devono gestire correttamente i GTID per evitare conflitti di replica dopo il restore Quando crea problemi #I GTID richiedono attenzione durante le operazioni di backup e restore. Se si ripristina un dump su un server con GTID attivo senza impostare correttamente --set-gtid-purged, si possono generare conflitti che rompono la catena di replica.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/gtid/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eGTID\u003c/strong\u003e (Global Transaction Identifier) è un identificativo univoco assegnato automaticamente a ogni transazione committata su un server MySQL. Il formato è \u003ccode\u003eserver_uuid:transaction_id\u003c/code\u003e — ad esempio \u003ccode\u003e3E11FA47-71CA-11E1-9E33-C80AA9429562:23\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando il GTID è abilitato (\u003ccode\u003egtid_mode = ON\u003c/code\u003e), ogni transazione riceve un identificativo che la rende tracciabile su qualsiasi server del cluster di replica. Lo slave sa esattamente quali transazioni ha già eseguito e quali deve ancora ricevere, senza bisogno di specificare manualmente posizioni di binlog (file + offset).\u003c/p\u003e","title":"GTID"},{"content":"Hash join è una strategia di join progettata per grandi volumi di dati. Funziona in due fasi: prima costruisce una struttura dati in memoria, poi la usa per trovare le corrispondenze in modo efficiente.\nCome funziona #Il database legge la tabella più piccola (build side) e costruisce una hash table in memoria, indicizzando le righe per la colonna di join. Poi scansiona la tabella più grande (probe side) e per ogni riga cerca la corrispondenza nella hash table con un lookup O(1).\nLa complessità è lineare — proporzionale alla somma delle righe delle due tabelle, non al prodotto come nel nested loop. Non servono indici: la hash table sostituisce temporaneamente l\u0026rsquo;indice.\nQuando è la scelta giusta #L\u0026rsquo;optimizer sceglie l\u0026rsquo;hash join quando entrambe le tabelle sono grandi e non ci sono indici utili, oppure quando le statistiche indicano che il numero di righe da combinare è troppo alto per un nested loop efficiente. È una delle strategie più comuni nei data warehouse e nei report che aggregano milioni di righe.\nCosa può andare storto #Il punto debole è la memoria. La hash table deve stare in work_mem: se la tabella più piccola non ci sta, il database scrive batch su disco (batched hash join), con un degrado significativo delle performance.\nwork_mem troppo basso: la hash table viene spezzata in batch su disco, moltiplicando l\u0026rsquo;I/O Stime errate: l\u0026rsquo;optimizer sceglie come build side la tabella sbagliata perché le statistiche indicano meno righe di quelle reali Skew nei dati: se un valore nella colonna di join domina la maggior parte delle righe, un bucket della hash table diventa enorme mentre gli altri restano vuoti ","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/hash-join/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eHash join\u003c/strong\u003e è una strategia di join progettata per grandi volumi di dati. Funziona in due fasi: prima costruisce una struttura dati in memoria, poi la usa per trovare le corrispondenze in modo efficiente.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl database legge la tabella più piccola (build side) e costruisce una hash table in memoria, indicizzando le righe per la colonna di join. Poi scansiona la tabella più grande (probe side) e per ogni riga cerca la corrispondenza nella hash table con un lookup O(1).\u003c/p\u003e","title":"Hash Join"},{"content":"L\u0026rsquo;Hot Desk (hot desking) è un modello di organizzazione degli spazi di lavoro in cui le scrivanie non sono assegnate a singoli dipendenti. Chi viene in ufficio occupa una postazione libera, tipicamente prenotabile tramite un sistema digitale.\nCome funziona #Invece di 50 postazioni fisse per 50 dipendenti, l\u0026rsquo;azienda predispone 15-20 postazioni condivise (hot desk) attrezzate con monitor, docking station e connettività. I dipendenti prenotano la postazione nei giorni in cui devono essere in ufficio, usando le altre giornate in smart working.\nA cosa serve #Riduce drasticamente i costi immobiliari: da 50 postazioni a 15 si risparmiano circa il 70% dello spazio e dei costi correlati (affitto, utenze, pulizie, manutenzione). Lo spazio risparmiato può essere convertito in sale riunioni adeguate e aree collaborative.\nCosa può andare storto #Senza un sistema di prenotazione efficiente, si creano conflitti e frustrazione. I dipendenti che non hanno \u0026ldquo;la propria scrivania\u0026rdquo; possono sentirsi meno radicati nell\u0026rsquo;azienda. La soluzione è combinare hot desk con spazi personali (armadietti) e aree team dedicate.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/hot-desk/","section":"Glossario","summary":"\u003cp\u003eL\u0026rsquo;\u003cstrong\u003eHot Desk\u003c/strong\u003e (hot desking) è un modello di organizzazione degli spazi di lavoro in cui le scrivanie non sono assegnate a singoli dipendenti. Chi viene in ufficio occupa una postazione libera, tipicamente prenotabile tramite un sistema digitale.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eInvece di 50 postazioni fisse per 50 dipendenti, l\u0026rsquo;azienda predispone 15-20 postazioni condivise (hot desk) attrezzate con monitor, docking station e connettività. I dipendenti prenotano la postazione nei giorni in cui devono essere in ufficio, usando le altre giornate in smart working.\u003c/p\u003e","title":"Hot Desk"},{"content":"Le Huge Pages sono pagine di memoria da 2 MB, contro i 4 KB standard di Linux. Per un\u0026rsquo;SGA Oracle da 64 GB, passare da pagine da 4 KB (16,7 milioni di pagine) a Huge Pages da 2 MB (32.768 pagine) riduce di 500 volte il numero di entry nella Page Table.\nCome funziona #Si configurano tramite il parametro kernel vm.nr_hugepages in /etc/sysctl.d/. Il numero necessario si calcola dividendo la dimensione della SGA per 2 MB e aggiungendo un margine dell'1,5%. Dopo il riavvio dell\u0026rsquo;istanza Oracle, la SGA viene allocata nelle Huge Pages, verificabile da /proc/meminfo.\nA cosa serve #Riducono la pressione sul TLB (Translation Lookaside Buffer) della CPU, che può memorizzare solo poche migliaia di traduzioni indirizzo. Con pagine normali, il TLB va in overflow costante e la MMU deve gestire milioni di traduzioni — con un impatto misurabile su latch free wait e library cache contention.\nPerché è critico #È il singolo parametro più impattante per Oracle su Linux, e quello ignorato più spesso. L\u0026rsquo;installazione wizard non lo configura, la documentazione è in una nota MOS, e il sistema \u0026ldquo;funziona anche senza.\u0026rdquo; Ma le metriche prima/dopo parlano chiaro: library cache hit ratio dal 92% al 99,7%, CPU dal 78% al 41%.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/huge-pages/","section":"Glossario","summary":"\u003cp\u003eLe \u003cstrong\u003eHuge Pages\u003c/strong\u003e sono pagine di memoria da 2 MB, contro i 4 KB standard di Linux. Per un\u0026rsquo;SGA Oracle da 64 GB, passare da pagine da 4 KB (16,7 milioni di pagine) a Huge Pages da 2 MB (32.768 pagine) riduce di 500 volte il numero di entry nella Page Table.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSi configurano tramite il parametro kernel \u003ccode\u003evm.nr_hugepages\u003c/code\u003e in \u003ccode\u003e/etc/sysctl.d/\u003c/code\u003e. Il numero necessario si calcola dividendo la dimensione della SGA per 2 MB e aggiungendo un margine dell'1,5%. Dopo il riavvio dell\u0026rsquo;istanza Oracle, la SGA viene allocata nelle Huge Pages, verificabile da \u003ccode\u003e/proc/meminfo\u003c/code\u003e.\u003c/p\u003e","title":"Huge Pages"},{"content":"L\u0026rsquo;I/O Scheduler è il componente del kernel Linux che gestisce la coda delle richieste di lettura e scrittura verso i dispositivi a blocchi (dischi). Decide l\u0026rsquo;ordine di esecuzione delle richieste per ottimizzare il throughput e minimizzare la latenza.\nCome funziona #Linux offre diversi scheduler: cfq (Completely Fair Queuing, per desktop), deadline/mq-deadline (per server e database), noop/none (per SSD/NVMe). Per Oracle la raccomandazione è deadline, che serve le richieste minimizzando i seek del disco. Si configura via /sys/block/sdX/queue/scheduler e si rende permanente via GRUB.\nA cosa serve #Il cfq di default distribuisce equamente l\u0026rsquo;I/O tra i processi — ideale per un desktop, pessimo per un database che ha bisogno di priorità sulle richieste I/O critiche. deadline garantisce che nessuna richiesta resti in coda troppo a lungo, riducendo la latenza dei db file sequential read.\nCosa può andare storto #Lasciare il default (cfq o bfq su alcuni sistemi) significa che Oracle compete per l\u0026rsquo;I/O con tutti gli altri processi del sistema. Su un server dedicato al database è uno spreco: il database dovrebbe avere priorità assoluta sulle operazioni disco.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/io-scheduler/","section":"Glossario","summary":"\u003cp\u003eL\u0026rsquo;\u003cstrong\u003eI/O Scheduler\u003c/strong\u003e è il componente del kernel Linux che gestisce la coda delle richieste di lettura e scrittura verso i dispositivi a blocchi (dischi). Decide l\u0026rsquo;ordine di esecuzione delle richieste per ottimizzare il throughput e minimizzare la latenza.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLinux offre diversi scheduler: \u003ccode\u003ecfq\u003c/code\u003e (Completely Fair Queuing, per desktop), \u003ccode\u003edeadline\u003c/code\u003e/\u003ccode\u003emq-deadline\u003c/code\u003e (per server e database), \u003ccode\u003enoop\u003c/code\u003e/\u003ccode\u003enone\u003c/code\u003e (per SSD/NVMe). Per Oracle la raccomandazione è \u003ccode\u003edeadline\u003c/code\u003e, che serve le richieste minimizzando i seek del disco. Si configura via \u003ccode\u003e/sys/block/sdX/queue/scheduler\u003c/code\u003e e si rende permanente via GRUB.\u003c/p\u003e","title":"I/O Scheduler"},{"content":"Gli Interessi di Mora sono gli interessi che maturano automaticamente su ogni fattura pagata in ritardo rispetto al termine contrattuale. In base al D.Lgs. 231/2002 (recepimento della Direttiva UE 2011/7/UE), il tasso è pari al tasso BCE + 8 punti percentuali, senza bisogno di messa in mora formale.\nCome funziona #Dal giorno successivo alla scadenza della fattura, gli interessi maturano automaticamente. Il creditore ha diritto anche a un compenso forfettario di 40€ per ogni fattura pagata in ritardo, per le spese di recupero. Non serve inviare una diffida — il diritto nasce dalla legge.\nA cosa serve #Sono lo strumento legale principale per disincentivare i ritardi di pagamento. Nella teoria, dovrebbero rendere sconveniente per il debitore ritardare. Nella pratica italiana, quasi nessun consulente li richiede per paura di perdere il cliente — il che rende lo strumento inefficace.\nCosa può andare storto #Il costo reputazionale di richiedere gli interessi di mora è percepito come superiore al beneficio economico. Un consulente che manda una richiesta formale è un consulente che \u0026ldquo;non verrà più chiamato.\u0026rdquo; Il sistema si regge sulla docilità strutturale del fornitore — e funziona, finché funziona.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/interessi-di-mora/","section":"Glossario","summary":"\u003cp\u003eGli \u003cstrong\u003eInteressi di Mora\u003c/strong\u003e sono gli interessi che maturano automaticamente su ogni fattura pagata in ritardo rispetto al termine contrattuale. In base al D.Lgs. 231/2002 (recepimento della Direttiva UE 2011/7/UE), il tasso è pari al tasso BCE + 8 punti percentuali, senza bisogno di messa in mora formale.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eDal giorno successivo alla scadenza della fattura, gli interessi maturano automaticamente. Il creditore ha diritto anche a un compenso forfettario di 40€ per ogni fattura pagata in ritardo, per le spese di recupero. Non serve inviare una diffida — il diritto nasce dalla legge.\u003c/p\u003e","title":"Interessi di Mora"},{"content":"INTO OUTFILE è una clausola SQL di MySQL che permette di esportare il risultato di una query direttamente in un file sul filesystem del server database. È il metodo nativo per generare file CSV, TSV o con separatori personalizzati.\nCome funziona #La clausola si aggiunge alla fine di una SELECT e specifica il percorso del file di destinazione. I parametri FIELDS TERMINATED BY, ENCLOSED BY e LINES TERMINATED BY controllano il formato dell\u0026rsquo;output. Il file viene creato dall\u0026rsquo;utente di sistema MySQL (non dall\u0026rsquo;utente che esegue la query), quindi deve trovarsi in una directory con i permessi corretti.\nA cosa serve #INTO OUTFILE è utile per export massivi di dati dal database in file di testo strutturati. È il complemento di LOAD DATA INFILE, che fa l\u0026rsquo;operazione inversa (importa dati da file). Insieme formano il meccanismo nativo di MySQL per bulk import/export.\nQuando si usa #L\u0026rsquo;uso è vincolato alla direttiva secure-file-priv: il file di destinazione deve trovarsi nella directory autorizzata. Quando secure-file-priv blocca il percorso desiderato, l\u0026rsquo;alternativa è usare il client mysql da shell con -B -e e redirigere l\u0026rsquo;output, che non è soggetto alle stesse restrizioni.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/into-outfile/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eINTO OUTFILE\u003c/strong\u003e è una clausola SQL di MySQL che permette di esportare il risultato di una query direttamente in un file sul filesystem del server database. È il metodo nativo per generare file CSV, TSV o con separatori personalizzati.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa clausola si aggiunge alla fine di una \u003ccode\u003eSELECT\u003c/code\u003e e specifica il percorso del file di destinazione. I parametri \u003ccode\u003eFIELDS TERMINATED BY\u003c/code\u003e, \u003ccode\u003eENCLOSED BY\u003c/code\u003e e \u003ccode\u003eLINES TERMINATED BY\u003c/code\u003e controllano il formato dell\u0026rsquo;output. Il file viene creato dall\u0026rsquo;utente di sistema MySQL (non dall\u0026rsquo;utente che esegue la query), quindi deve trovarsi in una directory con i permessi corretti.\u003c/p\u003e","title":"INTO OUTFILE"},{"content":"Un Issue Tracker è un sistema per registrare, assegnare, prioritizzare e monitorare bug, richieste di funzionalità e task di progetto. Su GitHub è integrato direttamente nel repository del codice.\nCome funziona #Ogni problema o richiesta viene creata come \u0026ldquo;issue\u0026rdquo; con titolo, descrizione, label di categoria/priorità e assegnazione a uno sviluppatore. Le issue possono essere collegate ai branch e alle Pull Request: quando una PR che referenzia un\u0026rsquo;issue viene fusa, l\u0026rsquo;issue si chiude automaticamente. Questo crea una tracciabilità completa dal problema alla soluzione.\nA cosa serve #L\u0026rsquo;issue tracker sostituisce email, chat, fogli Excel e segnalazioni verbali con un sistema unico e strutturato. Ogni bug ha una storia: chi l\u0026rsquo;ha segnalato, chi ci sta lavorando, qual è lo stato, quale codice l\u0026rsquo;ha risolto. In progetti caotici, l\u0026rsquo;issue tracker è lo strumento che trasforma la confusione in visibilità.\nQuando si usa #Su ogni progetto software, indipendentemente dalla dimensione. L\u0026rsquo;alternativa — segnalazioni sparse su email, chat e Excel — è la causa principale della perdita di informazioni e della duplicazione del lavoro. GitHub Issues, Jira e Linear sono le piattaforme più diffuse.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/issue-tracker/","section":"Glossario","summary":"\u003cp\u003eUn \u003cstrong\u003eIssue Tracker\u003c/strong\u003e è un sistema per registrare, assegnare, prioritizzare e monitorare bug, richieste di funzionalità e task di progetto. Su GitHub è integrato direttamente nel repository del codice.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOgni problema o richiesta viene creata come \u0026ldquo;issue\u0026rdquo; con titolo, descrizione, label di categoria/priorità e assegnazione a uno sviluppatore. Le issue possono essere collegate ai branch e alle Pull Request: quando una PR che referenzia un\u0026rsquo;issue viene fusa, l\u0026rsquo;issue si chiude automaticamente. Questo crea una tracciabilità completa dal problema alla soluzione.\u003c/p\u003e","title":"Issue Tracker"},{"content":"IST (Incremental State Transfer) è il meccanismo con cui un nodo Galera che rientra nel cluster dopo un\u0026rsquo;assenza breve riceve solo le transazioni mancanti, senza dover scaricare l\u0026rsquo;intero dataset.\nCome funziona #Quando un nodo si riconnette al cluster, il donatore verifica se le transazioni mancanti sono ancora disponibili nel proprio gcache (Galera cache). Se il gap è coperto dal gcache, viene eseguito un IST: solo le transazioni mancanti vengono inviate al nodo, che le applica e torna in stato Synced. Se il gap supera il gcache, Galera ricade su un SST completo.\nA cosa serve #IST rende il rientro di un nodo nel cluster molto più veloce rispetto a un SST completo. Un nodo che è rimasto offline per qualche minuto o qualche ora può tornare operativo in pochi secondi, senza impatto sulle performance del cluster.\nQuando si usa #IST viene attivato automaticamente quando le condizioni lo permettono. La dimensione del gcache (gcache.size) determina quante transazioni il cluster può tenere in memoria per supportare IST. Un gcache più grande permette downtime più lunghi di un nodo senza necessità di SST.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/ist/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eIST\u003c/strong\u003e (Incremental State Transfer) è il meccanismo con cui un nodo Galera che rientra nel cluster dopo un\u0026rsquo;assenza breve riceve solo le transazioni mancanti, senza dover scaricare l\u0026rsquo;intero dataset.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando un nodo si riconnette al cluster, il donatore verifica se le transazioni mancanti sono ancora disponibili nel proprio gcache (Galera cache). Se il gap è coperto dal gcache, viene eseguito un IST: solo le transazioni mancanti vengono inviate al nodo, che le applica e torna in stato Synced. Se il gap supera il gcache, Galera ricade su un SST completo.\u003c/p\u003e","title":"IST"},{"content":"Kimball si riferisce a Ralph Kimball e alla sua metodologia di progettazione dei data warehouse, descritta nel libro The Data Warehouse Toolkit (prima edizione 1996, terza edizione 2013).\nL\u0026rsquo;approccio #La metodologia Kimball si basa su tre pilastri:\nDimensional modeling: organizzare i dati in star schema con fact table e dimension table, ottimizzati per le query analitiche Bottom-up: costruire il DWH partendo dai singoli data mart dipartimentali, integrandoli progressivamente tramite dimensioni conformi (conformed dimensions) Bus architecture: un framework per garantire coerenza tra i data mart attraverso dimensioni e fatti condivisi Le Slowly Changing Dimensions #Kimball ha definito la classificazione delle SCD (Slowly Changing Dimensions) nei tipi da 0 a 7, che è diventata lo standard de facto nel settore. Il Tipo 2 — con chiavi surrogate e date di validità — è il più usato per tracciare la storia delle dimensioni.\nKimball vs Inmon #L\u0026rsquo;alternativa principale è la metodologia di Bill Inmon, che propone un approccio top-down con un enterprise data warehouse normalizzato (3NF) da cui derivano i data mart. Le due metodologie non sono mutualmente esclusive e molti progetti reali adottano elementi di entrambe.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/kimball/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eKimball\u003c/strong\u003e si riferisce a Ralph Kimball e alla sua metodologia di progettazione dei data warehouse, descritta nel libro \u003cem\u003eThe Data Warehouse Toolkit\u003c/em\u003e (prima edizione 1996, terza edizione 2013).\u003c/p\u003e\n\u003ch2 id=\"lapproccio\" class=\"relative group\"\u003eL\u0026rsquo;approccio \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#lapproccio\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa metodologia Kimball si basa su tre pilastri:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eDimensional modeling\u003c/strong\u003e: organizzare i dati in star schema con fact table e dimension table, ottimizzati per le query analitiche\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eBottom-up\u003c/strong\u003e: costruire il DWH partendo dai singoli data mart dipartimentali, integrandoli progressivamente tramite dimensioni conformi (conformed dimensions)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eBus architecture\u003c/strong\u003e: un framework per garantire coerenza tra i data mart attraverso dimensioni e fatti condivisi\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"le-slowly-changing-dimensions\" class=\"relative group\"\u003eLe Slowly Changing Dimensions \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#le-slowly-changing-dimensions\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eKimball ha definito la classificazione delle SCD (Slowly Changing Dimensions) nei tipi da 0 a 7, che è diventata lo standard de facto nel settore. Il Tipo 2 — con chiavi surrogate e date di validità — è il più usato per tracciare la storia delle dimensioni.\u003c/p\u003e","title":"Kimball"},{"content":"Il Knowledge Transfer (trasferimento di conoscenza) è il processo attraverso cui competenze, informazioni e know-how vengono trasferiti da chi li possiede a chi ne ha bisogno — tra colleghi, tra team, o tra persone e sistemi di documentazione.\nCome funziona #Può essere formale (documentazione, sessioni di training, wiki) o informale (pair programming, mentoring, affiancamento). L\u0026rsquo;AI può accelerare il knowledge transfer generando documentazione a partire dal codice, dai commit e dalle issue — non perfetta, ma sufficiente per non perdere conoscenza quando qualcuno lascia il progetto.\nA cosa serve #Ogni progetto IT dipende dalla conoscenza tacita delle persone che ci lavorano. Quando un senior developer lascia il team senza aver documentato le sue decisioni architetturali, il costo della perdita è invisibile ma enorme: settimane di reverse engineering, bug introdotti per incomprensione, decisioni ripetute perché nessuno ricorda il razionale.\nPerché è critico #È uno dei tre ambiti dove l\u0026rsquo;AI genera valore concreto nel project management. Nessuno documenta volentieri — l\u0026rsquo;AI può colmare questo gap. Ma il knowledge transfer non è solo documentazione: è anche la capacità di trasferire contesto, motivazioni e lezioni apprese, non solo istruzioni operative.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/knowledge-transfer/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eKnowledge Transfer\u003c/strong\u003e (trasferimento di conoscenza) è il processo attraverso cui competenze, informazioni e know-how vengono trasferiti da chi li possiede a chi ne ha bisogno — tra colleghi, tra team, o tra persone e sistemi di documentazione.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003ePuò essere formale (documentazione, sessioni di training, wiki) o informale (pair programming, mentoring, affiancamento). L\u0026rsquo;AI può accelerare il knowledge transfer generando documentazione a partire dal codice, dai commit e dalle issue — non perfetta, ma sufficiente per non perdere conoscenza quando qualcuno lascia il progetto.\u003c/p\u003e","title":"Knowledge Transfer"},{"content":"KPI (Key Performance Indicator) è una metrica quantificabile usata per valutare il successo di un\u0026rsquo;attività, un progetto o un\u0026rsquo;organizzazione rispetto a obiettivi predefiniti. Nel contesto del lavoro da remoto, i KPI sostituiscono la presenza fisica come indicatore di produttività.\nCome funziona #Un KPI efficace è specifico, misurabile e legato a un obiettivo concreto. Nella consulenza IT: ticket chiusi, codice rilasciato, SLA rispettati, clienti soddisfatti. Non \u0026ldquo;ore alla scrivania\u0026rdquo; — perché le ore non misurano il valore prodotto, misurano solo il tempo trascorso.\nA cosa serve #Permette di gestire il lavoro per obiettivi invece che per presenza. Un consulente che chiude 20 ticket da casa è più produttivo di uno che ne chiude 8 in ufficio. I KPI rendono questa differenza visibile e misurabile, togliendo spazio alla percezione soggettiva.\nPerché è critico #Le aziende che non sanno definire KPI chiari non possono adottare lo smart working in modo serio. Senza metriche oggettive, il management ricade nel controllo visivo — \u0026ldquo;se ti vedo alla scrivania, stai lavorando\u0026rdquo; — che è il presupposto sbagliato alla base del presenteismo.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/kpi/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eKPI\u003c/strong\u003e (Key Performance Indicator) è una metrica quantificabile usata per valutare il successo di un\u0026rsquo;attività, un progetto o un\u0026rsquo;organizzazione rispetto a obiettivi predefiniti. Nel contesto del lavoro da remoto, i KPI sostituiscono la presenza fisica come indicatore di produttività.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn KPI efficace è specifico, misurabile e legato a un obiettivo concreto. Nella consulenza IT: ticket chiusi, codice rilasciato, SLA rispettati, clienti soddisfatti. Non \u0026ldquo;ore alla scrivania\u0026rdquo; — perché le ore non misurano il valore prodotto, misurano solo il tempo trascorso.\u003c/p\u003e","title":"KPI"},{"content":"Il Least Privilege (principio del privilegio minimo) è un principio fondamentale della sicurezza informatica: ogni utente, processo o sistema deve avere solo i permessi strettamente necessari per svolgere la propria funzione, niente di più.\nCome funziona #In ambito database, il principio si applica assegnando privilegi granulari: SELECT se l\u0026rsquo;utente deve solo leggere, SELECT + INSERT + UPDATE se deve anche scrivere, mai ALL PRIVILEGES se non strettamente necessario. Combinato con il modello utente@host di MySQL, il principio può essere applicato anche in base all\u0026rsquo;origine della connessione.\nA cosa serve #Limitare i privilegi riduce la superficie di attacco. Se un\u0026rsquo;applicazione viene compromessa, l\u0026rsquo;attaccante eredita i privilegi dell\u0026rsquo;utente database dell\u0026rsquo;applicazione. Se quell\u0026rsquo;utente ha solo SELECT su un database specifico, il danno è contenuto. Se ha ALL PRIVILEGES, l\u0026rsquo;intero server è a rischio.\nQuando si usa #Sempre. Il principio del least privilege è applicabile in ogni contesto: utenti database, utenti di sistema operativo, ruoli applicativi, account di servizio. La tentazione di assegnare privilegi ampi \u0026ldquo;per non avere problemi\u0026rdquo; è la causa più comune di incidenti di sicurezza evitabili.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/least-privilege/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eLeast Privilege\u003c/strong\u003e (principio del privilegio minimo) è un principio fondamentale della sicurezza informatica: ogni utente, processo o sistema deve avere solo i permessi strettamente necessari per svolgere la propria funzione, niente di più.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIn ambito database, il principio si applica assegnando privilegi granulari: \u003ccode\u003eSELECT\u003c/code\u003e se l\u0026rsquo;utente deve solo leggere, \u003ccode\u003eSELECT + INSERT + UPDATE\u003c/code\u003e se deve anche scrivere, mai \u003ccode\u003eALL PRIVILEGES\u003c/code\u003e se non strettamente necessario. Combinato con il modello \u003ccode\u003eutente@host\u003c/code\u003e di MySQL, il principio può essere applicato anche in base all\u0026rsquo;origine della connessione.\u003c/p\u003e","title":"Least Privilege"},{"content":"Lift-and-Shift (rehosting) è una strategia di migrazione che consiste nello spostare un sistema da un ambiente all\u0026rsquo;altro — tipicamente da on-premise a cloud — senza modificarne l\u0026rsquo;architettura, il codice applicativo o la configurazione. Si prende il sistema così com\u0026rsquo;è e lo si \u0026ldquo;solleva e sposta\u0026rdquo;.\nCome funziona #L\u0026rsquo;infrastruttura viene replicata nell\u0026rsquo;ambiente di destinazione: stesse macchine virtuali, stessi database, stessi middleware. Il vantaggio è la velocità: non c\u0026rsquo;è riscrittura del codice, non c\u0026rsquo;è redesign architetturale. Il rischio è portarsi dietro tutti i problemi dell\u0026rsquo;ambiente originale, incluse inefficienze e debito tecnico.\nQuando si usa #Quando la priorità è uscire rapidamente da un datacenter (fine contratto, dismissione hardware), quando il budget non permette una rearchitettura, o come prima fase di una migrazione incrementale dove i componenti vengono poi modernizzati uno alla volta.\nCosa può andare storto #Un lift-and-shift verso il cloud senza ottimizzazione può costare più dell\u0026rsquo;infrastruttura on-premise originale. Le applicazioni non progettate per il cloud non sfruttano elasticità, auto-scaling e servizi managed. Il risultato è spesso un datacenter privato ricostruito nel cloud a un prezzo superiore.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/lift-and-shift/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eLift-and-Shift\u003c/strong\u003e (rehosting) è una strategia di migrazione che consiste nello spostare un sistema da un ambiente all\u0026rsquo;altro — tipicamente da on-premise a cloud — senza modificarne l\u0026rsquo;architettura, il codice applicativo o la configurazione. Si prende il sistema così com\u0026rsquo;è e lo si \u0026ldquo;solleva e sposta\u0026rdquo;.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eL\u0026rsquo;infrastruttura viene replicata nell\u0026rsquo;ambiente di destinazione: stesse macchine virtuali, stessi database, stessi middleware. Il vantaggio è la velocità: non c\u0026rsquo;è riscrittura del codice, non c\u0026rsquo;è redesign architetturale. Il rischio è portarsi dietro tutti i problemi dell\u0026rsquo;ambiente originale, incluse inefficienze e debito tecnico.\u003c/p\u003e","title":"Lift-and-Shift"},{"content":"Un Local Index è un indice Oracle creato su una tabella partizionata, che viene automaticamente partizionato con la stessa chiave e gli stessi limiti della tabella. Ogni partizione della tabella ha una corrispondente partizione di indice.\nCome funziona #Quando si crea un indice con la clausola LOCAL, Oracle crea una partizione di indice per ogni partizione della tabella. Se la tabella ha 100 partizioni mensili, l\u0026rsquo;indice avrà 100 partizioni corrispondenti. Le operazioni DDL su una partizione (DROP, TRUNCATE, SPLIT) invalidano solo la partizione di indice corrispondente, non l\u0026rsquo;intero indice.\nA cosa serve #Il Local Index è la scelta preferita per indici su tabelle partizionate perché mantiene l\u0026rsquo;indipendenza delle partizioni. Un DROP PARTITION richiede meno di un secondo e non invalida nessun altro indice. Con un indice globale, la stessa operazione invaliderebbe l\u0026rsquo;intero indice, richiedendo ore di rebuild.\nQuando si usa #Si usa quando l\u0026rsquo;indice include la chiave di partizione o quando le query filtrano sempre sulla colonna di partizione. Per lookup puntuali su colonne non-partition (es. primary key), serve invece un indice globale. La regola: local dove possibile, global solo dove necessario.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/local-index/","section":"Glossario","summary":"\u003cp\u003eUn \u003cstrong\u003eLocal Index\u003c/strong\u003e è un indice Oracle creato su una tabella partizionata, che viene automaticamente partizionato con la stessa chiave e gli stessi limiti della tabella. Ogni partizione della tabella ha una corrispondente partizione di indice.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando si crea un indice con la clausola \u003ccode\u003eLOCAL\u003c/code\u003e, Oracle crea una partizione di indice per ogni partizione della tabella. Se la tabella ha 100 partizioni mensili, l\u0026rsquo;indice avrà 100 partizioni corrispondenti. Le operazioni DDL su una partizione (DROP, TRUNCATE, SPLIT) invalidano solo la partizione di indice corrispondente, non l\u0026rsquo;intero indice.\u003c/p\u003e","title":"Local Index"},{"content":"MERGE è un\u0026rsquo;istruzione SQL che combina le operazioni di INSERT e UPDATE (e opzionalmente DELETE) in un unico statement. Se il record esiste lo aggiorna, se non esiste lo inserisce. È spesso chiamata informalmente \u0026ldquo;upsert\u0026rdquo;.\nSintassi Oracle #MERGE INTO tabella_destinazione d USING tabella_sorgente s ON (d.chiave = s.chiave) WHEN MATCHED THEN UPDATE SET d.campo = s.campo WHEN NOT MATCHED THEN INSERT (chiave, campo) VALUES (s.chiave, s.campo); Uso nel data warehouse #Nel contesto ETL, il MERGE è il meccanismo base per caricare le tabelle dimensionali:\nSCD Tipo 1: un singolo MERGE che aggiorna i record esistenti e inserisce quelli nuovi SCD Tipo 2: il MERGE viene usato nella prima fase per chiudere i record modificati (impostando la data di fine validità), seguito da un INSERT per le nuove versioni Disponibilità # Oracle: supporto completo dalla versione 9i PostgreSQL: non ha MERGE nativo fino alla versione 15. In alternativa si usa INSERT ... ON CONFLICT (upsert) MySQL: usa INSERT ... ON DUPLICATE KEY UPDATE come alternativa SQL Server: supporto completo con sintassi simile a Oracle ","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/merge-sql/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eMERGE\u003c/strong\u003e è un\u0026rsquo;istruzione SQL che combina le operazioni di INSERT e UPDATE (e opzionalmente DELETE) in un unico statement. Se il record esiste lo aggiorna, se non esiste lo inserisce. È spesso chiamata informalmente \u0026ldquo;upsert\u0026rdquo;.\u003c/p\u003e\n\u003ch2 id=\"sintassi-oracle\" class=\"relative group\"\u003eSintassi Oracle \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#sintassi-oracle\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eMERGE\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eINTO\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etabella_destinazione\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ed\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eUSING\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etabella_sorgente\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eON\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ed\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echiave\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echiave\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eWHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMATCHED\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eTHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eUPDATE\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eSET\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"n\"\u003ed\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecampo\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecampo\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eWHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eNOT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMATCHED\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eTHEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eINSERT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003echiave\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecampo\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"k\"\u003eVALUES\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echiave\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecampo\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"uso-nel-data-warehouse\" class=\"relative group\"\u003eUso nel data warehouse \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#uso-nel-data-warehouse\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eNel contesto ETL, il MERGE è il meccanismo base per caricare le tabelle dimensionali:\u003c/p\u003e","title":"MERGE"},{"content":"La Mobilità Sostenibile è un approccio ai trasporti urbani che privilegia l\u0026rsquo;uso di mezzi a basso impatto ambientale — bicicletta, trasporto pubblico, veicoli elettrici, car sharing — rispetto all\u0026rsquo;auto privata a combustione interna.\nCome funziona #Si basa su un cambio di paradigma: invece di costruire più strade per più auto, si investe in infrastrutture ciclabili, trasporto pubblico efficiente e incentivi per la mobilità attiva. Città come Amsterdam, Copenhagen e Monaco dimostrano che il modello funziona su larga scala.\nA cosa serve #Riduce emissioni, traffico, costi individuali e collettivi, inquinamento acustico e occupazione di suolo. Per il singolo pendolare, significa risparmiare fino a 5.450€ all\u0026rsquo;anno e 455 ore di tempo rispetto all\u0026rsquo;auto — due mesi e mezzo di vita restituiti.\nPerché è critico #Roma ha 300 giorni di sole all\u0026rsquo;anno, un clima mite e distanze urbane contenute. È paradossalmente una delle città italiane più adatte alla bicicletta. Mancano le infrastrutture e il coraggio di cambiare abitudini. Il modello ideale combina smart working (3 giorni da remoto) con mobilità sostenibile (2 giorni in bici): da 13 ore settimanali in viaggio a 1 ora e 12 minuti.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/mobilita-sostenibile/","section":"Glossario","summary":"\u003cp\u003eLa \u003cstrong\u003eMobilità Sostenibile\u003c/strong\u003e è un approccio ai trasporti urbani che privilegia l\u0026rsquo;uso di mezzi a basso impatto ambientale — bicicletta, trasporto pubblico, veicoli elettrici, car sharing — rispetto all\u0026rsquo;auto privata a combustione interna.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSi basa su un cambio di paradigma: invece di costruire più strade per più auto, si investe in infrastrutture ciclabili, trasporto pubblico efficiente e incentivi per la mobilità attiva. Città come Amsterdam, Copenhagen e Monaco dimostrano che il modello funziona su larga scala.\u003c/p\u003e","title":"Mobilità Sostenibile"},{"content":"MVCC (Multi-Version Concurrency Control) è il modello di concorrenza usato da PostgreSQL per gestire l\u0026rsquo;accesso simultaneo ai dati. Ogni UPDATE crea una nuova versione della riga e segna la vecchia come \u0026ldquo;morta\u0026rdquo;; ogni DELETE marca la riga come non più visibile. Le letture non bloccano le scritture e viceversa.\nCome funziona #Ogni transazione vede uno snapshot consistente del database al momento del suo inizio. Le righe modificate da altre transazioni non ancora committate sono invisibili. Questo elimina la necessità di lock esclusivi sulle letture, permettendo alta concorrenza — ma genera \u0026ldquo;spazzatura\u0026rdquo; sotto forma di dead tuples che devono essere puliti dal VACUUM.\nA cosa serve #MVCC è il compromesso architetturale di PostgreSQL: concorrenza elevata senza lock, al prezzo di dover gestire la pulizia delle versioni obsolete. È un prezzo ragionevole — a patto che l\u0026rsquo;autovacuum sia configurato correttamente per tenere il passo con il ritmo di modifica delle tabelle.\nPerché è critico #Se il VACUUM non riesce a tenere il passo con la velocità di generazione dei dead tuples, le tabelle si gonfiano (bloat), le scansioni sequenziali rallentano e gli indici diventano inefficienti. Il pattern classico: lunedì il database va bene, venerdì è un disastro.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/mvcc/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eMVCC\u003c/strong\u003e (Multi-Version Concurrency Control) è il modello di concorrenza usato da PostgreSQL per gestire l\u0026rsquo;accesso simultaneo ai dati. Ogni UPDATE crea una nuova versione della riga e segna la vecchia come \u0026ldquo;morta\u0026rdquo;; ogni DELETE marca la riga come non più visibile. Le letture non bloccano le scritture e viceversa.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOgni transazione vede uno snapshot consistente del database al momento del suo inizio. Le righe modificate da altre transazioni non ancora committate sono invisibili. Questo elimina la necessità di lock esclusivi sulle letture, permettendo alta concorrenza — ma genera \u0026ldquo;spazzatura\u0026rdquo; sotto forma di dead tuples che devono essere puliti dal VACUUM.\u003c/p\u003e","title":"MVCC"},{"content":"mydumper è un tool open source di backup logico per MySQL e MariaDB che implementa il parallelismo reale: non solo tra tabelle diverse, ma anche all\u0026rsquo;interno della stessa tabella, dividendola in chunk basati sulla primary key.\nCome funziona #mydumper si connette al server MySQL, acquisisce una snapshot consistente con FLUSH TABLES WITH READ LOCK (o --trx-consistency-only per evitare lock globali su InnoDB), poi distribuisce il lavoro tra thread multipli. Ogni tabella grande viene spezzata in chunk — per default basati sui range della primary key — e ogni chunk viene esportato da un thread separato.\nL\u0026rsquo;output non è un singolo file SQL ma una directory con un file per ogni tabella (o per ogni chunk), più i file di metadati, schema e stored procedure.\nIl restore con myloader #Il compagno di mydumper è myloader, che carica i file in parallelo disabilitando i check delle foreign key e ricostruendo gli indici alla fine. Questo approccio rende il restore significativamente più veloce rispetto al caricamento sequenziale di un singolo file SQL.\nQuando si usa #mydumper è la scelta raccomandata per database di produzione sopra i 10 GB dove la velocità di dump e restore è critica. Su un database da 60 GB con 8 thread, un dump che con mysqldump richiede 3-4 ore si completa in 20-25 minuti.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/mydumper/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003emydumper\u003c/strong\u003e è un tool open source di backup logico per MySQL e MariaDB che implementa il parallelismo reale: non solo tra tabelle diverse, ma anche all\u0026rsquo;interno della stessa tabella, dividendola in chunk basati sulla primary key.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003emydumper si connette al server MySQL, acquisisce una snapshot consistente con \u003ccode\u003eFLUSH TABLES WITH READ LOCK\u003c/code\u003e (o \u003ccode\u003e--trx-consistency-only\u003c/code\u003e per evitare lock globali su InnoDB), poi distribuisce il lavoro tra thread multipli. Ogni tabella grande viene spezzata in chunk — per default basati sui range della primary key — e ogni chunk viene esportato da un thread separato.\u003c/p\u003e","title":"mydumper"},{"content":"mysqlbinlog è l\u0026rsquo;utility da riga di comando fornita con MySQL per leggere e decodificare il contenuto dei file binary log. È l\u0026rsquo;unico strumento in grado di convertire il formato binario dei binlog in output leggibile o in istruzioni SQL rieseguibili.\nCome funziona #mysqlbinlog legge i file binlog e produce output in formato testo. Supporta diversi filtri:\nPer intervallo temporale: --start-datetime e --stop-datetime per limitare l\u0026rsquo;output a una finestra temporale Per database: --database per filtrare gli eventi di un database specifico Per posizione: --start-position e --stop-position per selezionare eventi specifici Con il formato ROW, il flag --verbose decodifica le modifiche riga per riga in formato pseudo-SQL commentato, altrimenti l\u0026rsquo;output è un blob binario illeggibile.\nA cosa serve #mysqlbinlog è utilizzato in due scenari principali:\nPoint-in-time recovery: estrarre e riapplicare gli eventi dal backup fino al momento desiderato, piping l\u0026rsquo;output direttamente nel client mysql Debug di replica: analizzare gli eventi per capire cosa è stato replicato, identificare transazioni problematiche o ricostruire la sequenza di operazioni che ha causato un problema Quando si usa #mysqlbinlog è essenziale ogni volta che serve ispezionare cosa è successo nel database dopo un incidente, o quando si deve eseguire un point-in-time recovery. Richiede accesso ai file binlog sul filesystem del server o la possibilità di connettersi al server con --read-from-remote-server.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/mysqlbinlog/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003emysqlbinlog\u003c/strong\u003e è l\u0026rsquo;utility da riga di comando fornita con MySQL per leggere e decodificare il contenuto dei file binary log. È l\u0026rsquo;unico strumento in grado di convertire il formato binario dei binlog in output leggibile o in istruzioni SQL rieseguibili.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003emysqlbinlog legge i file binlog e produce output in formato testo. Supporta diversi filtri:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePer intervallo temporale\u003c/strong\u003e: \u003ccode\u003e--start-datetime\u003c/code\u003e e \u003ccode\u003e--stop-datetime\u003c/code\u003e per limitare l\u0026rsquo;output a una finestra temporale\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePer database\u003c/strong\u003e: \u003ccode\u003e--database\u003c/code\u003e per filtrare gli eventi di un database specifico\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePer posizione\u003c/strong\u003e: \u003ccode\u003e--start-position\u003c/code\u003e e \u003ccode\u003e--stop-position\u003c/code\u003e per selezionare eventi specifici\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eCon il formato ROW, il flag \u003ccode\u003e--verbose\u003c/code\u003e decodifica le modifiche riga per riga in formato pseudo-SQL commentato, altrimenti l\u0026rsquo;output è un blob binario illeggibile.\u003c/p\u003e","title":"mysqlbinlog"},{"content":"mysqldump è l\u0026rsquo;utility di backup logico inclusa di serie in ogni installazione di MySQL e MariaDB. Produce un file SQL contenente tutte le istruzioni (CREATE TABLE, INSERT) necessarie per ricostruire completamente schema e dati di un database.\nCome funziona #mysqldump si connette al server MySQL e legge le tabelle una alla volta, generando le istruzioni SQL corrispondenti in output. L\u0026rsquo;operazione è rigorosamente single-threaded: una tabella dopo l\u0026rsquo;altra, una riga dopo l\u0026rsquo;altra. Il file prodotto può essere compresso esternamente (gzip, zstd) ma lo strumento stesso non offre compressione nativa.\nCon l\u0026rsquo;opzione --single-transaction, il dump avviene all\u0026rsquo;interno di una transazione con isolation level REPEATABLE READ, che garantisce una snapshot consistente su tabelle InnoDB senza acquisire lock sulle scritture.\nA cosa serve #mysqldump è lo strumento standard per:\nBackup logico di database di piccole e medie dimensioni Migrazioni tra versioni diverse di MySQL Export di singole tabelle o database per trasferimento tra ambienti Creazione di dump leggibili e ispezionabili manualmente Quando diventa un problema #Su database oltre i 10-15 GB, il dump single-threaded diventa un collo di bottiglia. Un database da 60 GB può richiedere 3-4 ore di dump e altrettante di restore. La mancanza di parallelismo è il limite strutturale: non c\u0026rsquo;è modo di velocizzare il processo se non passando a strumenti come mydumper.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/mysqldump/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003emysqldump\u003c/strong\u003e è l\u0026rsquo;utility di backup logico inclusa di serie in ogni installazione di MySQL e MariaDB. Produce un file SQL contenente tutte le istruzioni (CREATE TABLE, INSERT) necessarie per ricostruire completamente schema e dati di un database.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003emysqldump si connette al server MySQL e legge le tabelle una alla volta, generando le istruzioni SQL corrispondenti in output. L\u0026rsquo;operazione è rigorosamente single-threaded: una tabella dopo l\u0026rsquo;altra, una riga dopo l\u0026rsquo;altra. Il file prodotto può essere compresso esternamente (gzip, zstd) ma lo strumento stesso non offre compressione nativa.\u003c/p\u003e","title":"mysqldump"},{"content":"mysqlpump è l\u0026rsquo;utility di backup logico introdotta da Oracle in MySQL 5.7 come evoluzione di mysqldump. La differenza principale è il supporto per il parallelismo a livello di tabella e la compressione nativa dell\u0026rsquo;output (zlib, lz4, zstd).\nCome funziona #mysqlpump può dumpare più tabelle contemporaneamente usando thread paralleli, configurabili con --default-parallelism. La compressione viene applicata direttamente durante il dump, senza bisogno di pipe esterne verso gzip. Supporta anche il dump selettivo di utenti e account MySQL.\nIl parallelismo però opera solo a livello di tabella intera: se una singola tabella è molto più grande delle altre, un thread si trascina da solo mentre gli altri hanno già finito.\nIl problema della consistenza #Con il parallelismo attivo, mysqlpump non garantisce consistenza tra tabelle diverse — tabelle esportate da thread differenti possono riflettere momenti diversi nel tempo. Questo è un limite critico per backup di produzione su database relazionali con foreign key.\nStato attuale #Oracle ha dichiarato mysqlpump deprecato in MySQL 8.0.34 e lo ha rimosso completamente in MySQL 8.4. Per chi cerca parallelismo nel backup logico, mydumper è l\u0026rsquo;alternativa consigliata.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/mysqlpump/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003emysqlpump\u003c/strong\u003e è l\u0026rsquo;utility di backup logico introdotta da Oracle in MySQL 5.7 come evoluzione di mysqldump. La differenza principale è il supporto per il parallelismo a livello di tabella e la compressione nativa dell\u0026rsquo;output (zlib, lz4, zstd).\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003emysqlpump può dumpare più tabelle contemporaneamente usando thread paralleli, configurabili con \u003ccode\u003e--default-parallelism\u003c/code\u003e. La compressione viene applicata direttamente durante il dump, senza bisogno di pipe esterne verso gzip. Supporta anche il dump selettivo di utenti e account MySQL.\u003c/p\u003e","title":"mysqlpump"},{"content":"Nested loop è la strategia di join più semplice: per ogni riga della tabella esterna, il database cerca le righe corrispondenti nella tabella interna. Funziona come un doppio ciclo for annidato — da qui il nome.\nCome funziona #L\u0026rsquo;optimizer sceglie una tabella come \u0026ldquo;esterna\u0026rdquo; (outer) e una come \u0026ldquo;interna\u0026rdquo; (inner). Per ogni riga della tabella esterna, esegue una ricerca nella tabella interna sulla colonna di join. Se la tabella interna ha un indice sulla colonna di join, ogni ricerca è un accesso diretto via B-tree. Senza indice, ogni ricerca diventa un sequential scan completo.\nQuando è la scelta giusta #Il nested loop è imbattibile quando la tabella esterna ha poche righe e la tabella interna ha un indice sulla colonna di join. Un join su 100 righe esterne con un indice B-tree sulla tabella interna è praticamente istantaneo: poche iterazioni, accesso diretto, memoria minima.\nÈ anche la strategia preferita per le lookup sulle dimensioni nei data warehouse, dove si unisce una fact table filtrata (poche righe) con una dimension table indicizzata.\nCosa può andare storto #Diventa un disastro quando l\u0026rsquo;optimizer lo sceglie su dataset grandi per errore — tipicamente perché le statistiche sottostimano il numero di righe. Un nested loop su 2 milioni di righe esterne significa 2 milioni di lookup nella tabella interna. Senza indice, ogni lookup è uno scan completo.\nIn questi casi un hash join o un merge join sarebbero ordini di grandezza più veloci. La causa è quasi sempre una stima di cardinalità sbagliata: statistiche obsolete o default_statistics_target troppo basso.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/nested-loop/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eNested loop\u003c/strong\u003e è la strategia di join più semplice: per ogni riga della tabella esterna, il database cerca le righe corrispondenti nella tabella interna. Funziona come un doppio ciclo \u003ccode\u003efor\u003c/code\u003e annidato — da qui il nome.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eL\u0026rsquo;optimizer sceglie una tabella come \u0026ldquo;esterna\u0026rdquo; (outer) e una come \u0026ldquo;interna\u0026rdquo; (inner). Per ogni riga della tabella esterna, esegue una ricerca nella tabella interna sulla colonna di join. Se la tabella interna ha un indice sulla colonna di join, ogni ricerca è un accesso diretto via B-tree. Senza indice, ogni ricerca diventa un sequential scan completo.\u003c/p\u003e","title":"Nested Loop"},{"content":"NOLOGGING è una modalità Oracle che disabilita la generazione di redo log durante operazioni di caricamento massivo. Le operazioni completano molto più velocemente, ma i dati non sono recuperabili tramite redo in caso di crash prima di un backup.\nCome funziona #Quando un segmento (tabella, indice, partizione) è in modalità NOLOGGING, le operazioni bulk come CTAS, INSERT /*+ APPEND */ e ALTER TABLE MOVE non scrivono redo log per i blocchi dati. Su una copia di 380 GB, questo elimina la generazione di altrettanti GB di redo, evitando di saturare l\u0026rsquo;area di archivelog e riducendo i tempi da giorni a ore.\nA cosa serve #NOLOGGING è essenziale per le operazioni di migrazione su tabelle di grandi dimensioni. Senza NOLOGGING, un CTAS di 380 GB genererebbe 380 GB di redo log, mandando il sistema in archivelog per giorni. Con NOLOGGING, la stessa operazione completa in poche ore con impatto minimo sul sistema.\nQuando si usa #Si attiva prima dell\u0026rsquo;operazione bulk e si disattiva subito dopo (ALTER TABLE ... LOGGING). È obbligatorio eseguire un backup RMAN immediatamente dopo, perché i segmenti NOLOGGING non sono recuperabili con un restore dai redo. Mai lasciare NOLOGGING attivo permanentemente su tabelle di produzione.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/nologging/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eNOLOGGING\u003c/strong\u003e è una modalità Oracle che disabilita la generazione di redo log durante operazioni di caricamento massivo. Le operazioni completano molto più velocemente, ma i dati non sono recuperabili tramite redo in caso di crash prima di un backup.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando un segmento (tabella, indice, partizione) è in modalità NOLOGGING, le operazioni bulk come CTAS, \u003ccode\u003eINSERT /*+ APPEND */\u003c/code\u003e e \u003ccode\u003eALTER TABLE MOVE\u003c/code\u003e non scrivono redo log per i blocchi dati. Su una copia di 380 GB, questo elimina la generazione di altrettanti GB di redo, evitando di saturare l\u0026rsquo;area di archivelog e riducendo i tempi da giorni a ore.\u003c/p\u003e","title":"NOLOGGING"},{"content":"Un Object Privilege in Oracle è un\u0026rsquo;autorizzazione che permette di eseguire operazioni su un oggetto specifico del database: una tabella, una vista, una sequenza o una procedura PL/SQL. Esempi tipici includono SELECT ON schema.tabella, INSERT ON schema.tabella e EXECUTE ON schema.procedura.\nCome funziona #Gli object privileges si assegnano con GRANT specificando l\u0026rsquo;operazione e l\u0026rsquo;oggetto target: GRANT SELECT ON app_owner.clienti TO srv_report. Possono essere assegnati a singoli utenti o a ruoli. A differenza dei system privileges, operano su un singolo oggetto e non conferiscono poteri globali sul database.\nA cosa serve #Gli object privileges sono lo strumento principale per implementare il principio del least privilege in Oracle. Permettono di costruire modelli di accesso granulari: un utente di reportistica ottiene solo SELECT, un utente applicativo ottiene SELECT + INSERT + UPDATE sulle tabelle operative, e così via. La combinazione con i ruoli custom crea architetture di sicurezza pulite e manutenibili.\nPerché è critico #La differenza tra un GRANT SELECT ON app_owner.clienti e un GRANT DBA è la differenza tra dare la chiave di una stanza e dare le chiavi dell\u0026rsquo;intero palazzo. In ambienti con centinaia di tabelle, gli object privileges si gestiscono tipicamente tramite blocchi PL/SQL che generano i grant automaticamente per tutte le tabelle di uno schema.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/object-privilege/","section":"Glossario","summary":"\u003cp\u003eUn \u003cstrong\u003eObject Privilege\u003c/strong\u003e in Oracle è un\u0026rsquo;autorizzazione che permette di eseguire operazioni su un oggetto specifico del database: una tabella, una vista, una sequenza o una procedura PL/SQL. Esempi tipici includono \u003ccode\u003eSELECT ON schema.tabella\u003c/code\u003e, \u003ccode\u003eINSERT ON schema.tabella\u003c/code\u003e e \u003ccode\u003eEXECUTE ON schema.procedura\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eGli object privileges si assegnano con \u003ccode\u003eGRANT\u003c/code\u003e specificando l\u0026rsquo;operazione e l\u0026rsquo;oggetto target: \u003ccode\u003eGRANT SELECT ON app_owner.clienti TO srv_report\u003c/code\u003e. Possono essere assegnati a singoli utenti o a ruoli. A differenza dei system privileges, operano su un singolo oggetto e non conferiscono poteri globali sul database.\u003c/p\u003e","title":"Object Privilege"},{"content":"OCI (Oracle Cloud Infrastructure) è la piattaforma cloud di Oracle, lanciata nella sua seconda generazione nel 2018. A differenza di altri cloud provider, OCI è progettata nativamente per i workload Oracle Database e offre vantaggi significativi in termini di licensing e performance.\nPerché OCI per Oracle Database #Il vantaggio principale riguarda il licensing. Su OCI, Oracle riconosce le proprie OCPU (Oracle CPU) con un rapporto 1:1 ai fini del conteggio delle licenze. Su altri cloud provider come AWS o Azure, il rapporto vCPU-licenze è meno favorevole e il rischio di audit è concreto.\nIl programma BYOL (Bring Your Own License) permette di riutilizzare le licenze on-premises esistenti su OCI senza costi aggiuntivi — un fattore decisivo per le aziende che hanno già investito in licenze Enterprise Edition.\nServizi principali per i DBA # Bare Metal DB Systems: server fisici dedicati con Oracle Database preinstallato VM DB Systems: istanze virtuali con configurazione flessibile (Flex shapes) Exadata Cloud Service: Exadata completo gestito in cloud Autonomous Database: database completamente gestito con tuning automatico Networking e connettività #OCI offre FastConnect per connessioni dedicate ad alta banda tra data center on-premises e la cloud region, oltre a VPN site-to-site per scenari con requisiti di banda inferiori. La latenza e la bandwidth del collegamento sono fattori critici nelle migrazioni con Data Guard cross-site.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/oci/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eOCI\u003c/strong\u003e (Oracle Cloud Infrastructure) è la piattaforma cloud di Oracle, lanciata nella sua seconda generazione nel 2018. A differenza di altri cloud provider, OCI è progettata nativamente per i workload Oracle Database e offre vantaggi significativi in termini di licensing e performance.\u003c/p\u003e\n\u003ch2 id=\"perché-oci-per-oracle-database\" class=\"relative group\"\u003ePerché OCI per Oracle Database \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#perch%c3%a9-oci-per-oracle-database\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl vantaggio principale riguarda il licensing. Su OCI, Oracle riconosce le proprie OCPU (Oracle CPU) con un rapporto 1:1 ai fini del conteggio delle licenze. Su altri cloud provider come AWS o Azure, il rapporto vCPU-licenze è meno favorevole e il rischio di audit è concreto.\u003c/p\u003e","title":"OCI"},{"content":"OLAP (Online Analytical Processing) indica un approccio all\u0026rsquo;elaborazione dei dati orientato all\u0026rsquo;analisi multidimensionale: aggregazioni, drill-down, confronti temporali, slice-and-dice su grandi volumi di dati storici.\nOLAP vs OLTP # Caratteristica OLAP OLTP Scopo Analisi e reporting Transazioni operative Modello dati Star schema, denormalizzato 3NF, normalizzato Query tipica Aggregazioni su milioni di righe Lettura/scrittura di poche righe Utenti Analisti, management Applicazioni, operatori Aggiornamento Batch (ETL periodico) Real-time Operazioni OLAP #Le operazioni fondamentali dell\u0026rsquo;analisi OLAP sono:\nDrill-down: dal livello aggregato al dettaglio Drill-up (roll-up): dal dettaglio all\u0026rsquo;aggregato Slice: selezionare una \u0026ldquo;fetta\u0026rdquo; dei dati fissando una dimensione (es. solo anno 2025) Dice: selezionare un sottocubo specificando più dimensioni Pivot: ruotare le dimensioni di analisi (righe ↔ colonne) Implementazioni # ROLAP (Relational OLAP): i dati restano in tabelle relazionali, le aggregazioni sono calcolate con query SQL. È l\u0026rsquo;approccio usato nei data warehouse con star schema MOLAP (Multidimensional OLAP): i dati sono pre-aggregati in strutture multidimensionali (cubi). Più veloce nelle query ma richiede più spazio e tempi di build HOLAP (Hybrid): combinazione dei due approcci ","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/olap/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eOLAP\u003c/strong\u003e (Online Analytical Processing) indica un approccio all\u0026rsquo;elaborazione dei dati orientato all\u0026rsquo;analisi multidimensionale: aggregazioni, drill-down, confronti temporali, slice-and-dice su grandi volumi di dati storici.\u003c/p\u003e\n\u003ch2 id=\"olap-vs-oltp\" class=\"relative group\"\u003eOLAP vs OLTP \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#olap-vs-oltp\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eCaratteristica\u003c/th\u003e\n          \u003cth\u003eOLAP\u003c/th\u003e\n          \u003cth\u003eOLTP\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eScopo\u003c/td\u003e\n          \u003ctd\u003eAnalisi e reporting\u003c/td\u003e\n          \u003ctd\u003eTransazioni operative\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eModello dati\u003c/td\u003e\n          \u003ctd\u003eStar schema, denormalizzato\u003c/td\u003e\n          \u003ctd\u003e3NF, normalizzato\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eQuery tipica\u003c/td\u003e\n          \u003ctd\u003eAggregazioni su milioni di righe\u003c/td\u003e\n          \u003ctd\u003eLettura/scrittura di poche righe\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eUtenti\u003c/td\u003e\n          \u003ctd\u003eAnalisti, management\u003c/td\u003e\n          \u003ctd\u003eApplicazioni, operatori\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eAggiornamento\u003c/td\u003e\n          \u003ctd\u003eBatch (ETL periodico)\u003c/td\u003e\n          \u003ctd\u003eReal-time\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"operazioni-olap\" class=\"relative group\"\u003eOperazioni OLAP \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#operazioni-olap\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLe operazioni fondamentali dell\u0026rsquo;analisi OLAP sono:\u003c/p\u003e","title":"OLAP"},{"content":"L\u0026rsquo;Outsourcing è la pratica di affidare lo sviluppo, la manutenzione o la gestione di sistemi IT a fornitori esterni all\u0026rsquo;azienda. Può riguardare progetti completi (sviluppo di un software custom) o servizi continuativi (gestione dell\u0026rsquo;infrastruttura, supporto applicativo).\nCome funziona #L\u0026rsquo;azienda cliente definisce i requisiti e stipula un contratto con un fornitore esterno che si impegna a realizzare il progetto. I modelli contrattuali più comuni sono: a corpo (prezzo fisso per risultato definito), a tempo e materiali (giornate-uomo fatturate), o ibridi. Il fornitore mette a disposizione un team di consulenti che lavorano sul progetto, spesso con rotazione periodica del personale.\nA cosa serve #Comprendere i rischi dell\u0026rsquo;outsourcing è fondamentale per decidere cosa esternalizzare e cosa tenere interno. I rischi principali sono: vendor lock-in, perdita di know-how, scope creep, turnover dei consulenti e disallineamento degli incentivi (il fornitore guadagna a tempo, non a risultato).\nQuando si usa #L\u0026rsquo;outsourcing può funzionare per attività commoditizzate o ben definite. Diventa rischioso per progetti strategici, custom e a lungo termine dove il know-how specifico del dominio è critico. L\u0026rsquo;alternativa spesso più efficace è un team interno piccolo e competente, eventualmente affiancato da consulenti per competenze specialistiche puntuali.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/outsourcing/","section":"Glossario","summary":"\u003cp\u003eL\u0026rsquo;\u003cstrong\u003eOutsourcing\u003c/strong\u003e è la pratica di affidare lo sviluppo, la manutenzione o la gestione di sistemi IT a fornitori esterni all\u0026rsquo;azienda. Può riguardare progetti completi (sviluppo di un software custom) o servizi continuativi (gestione dell\u0026rsquo;infrastruttura, supporto applicativo).\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eL\u0026rsquo;azienda cliente definisce i requisiti e stipula un contratto con un fornitore esterno che si impegna a realizzare il progetto. I modelli contrattuali più comuni sono: a corpo (prezzo fisso per risultato definito), a tempo e materiali (giornate-uomo fatturate), o ibridi. Il fornitore mette a disposizione un team di consulenti che lavorano sul progetto, spesso con rotazione periodica del personale.\u003c/p\u003e","title":"Outsourcing"},{"content":"Il Parking Lot è una lista visibile — su una lavagna, un documento condiviso o la chat — dove il facilitatore annota gli argomenti che emergono durante una riunione ma che non possono essere discussi nel tempo disponibile. Gli argomenti vengono \u0026ldquo;parcheggiati\u0026rdquo; e affrontati dopo la riunione con le sole persone coinvolte.\nCome funziona #Quando durante uno standup qualcuno solleva un problema complesso, il facilitatore dice: \u0026ldquo;Lo segno nel parking lot, ne parliamo dopo.\u0026rdquo; L\u0026rsquo;argomento non viene ignorato — viene solo spostato nel contesto giusto, dove può essere affrontato senza far perdere tempo a chi non è coinvolto.\nA cosa serve #È lo strumento più sottovalutato nella gestione degli standup e delle riunioni in generale. Permette di dire \u0026ldquo;ne parliamo dopo\u0026rdquo; senza che l\u0026rsquo;argomento venga dimenticato. Risolve il problema dei \u0026ldquo;thread killer\u0026rdquo; — quelle discussioni tra due persone che bloccano l\u0026rsquo;intera riunione.\nPerché è critico #Senza parking lot, il facilitatore ha due opzioni pessime: lasciare che la discussione si espanda (e lo standup sfora), oppure tagliare l\u0026rsquo;argomento (e qualcuno si sente ignorato). Il parking lot offre una terza via: riconoscere l\u0026rsquo;importanza dell\u0026rsquo;argomento e garantire che verrà affrontato, ma nel momento giusto.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/parking-lot/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eParking Lot\u003c/strong\u003e è una lista visibile — su una lavagna, un documento condiviso o la chat — dove il facilitatore annota gli argomenti che emergono durante una riunione ma che non possono essere discussi nel tempo disponibile. Gli argomenti vengono \u0026ldquo;parcheggiati\u0026rdquo; e affrontati dopo la riunione con le sole persone coinvolte.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando durante uno standup qualcuno solleva un problema complesso, il facilitatore dice: \u0026ldquo;Lo segno nel parking lot, ne parliamo dopo.\u0026rdquo; L\u0026rsquo;argomento non viene ignorato — viene solo spostato nel contesto giusto, dove può essere affrontato senza far perdere tempo a chi non è coinvolto.\u003c/p\u003e","title":"Parking Lot"},{"content":"La Partita IVA è il codice di identificazione fiscale assegnato ai lavoratori autonomi e alle imprese in Italia per le operazioni soggette a IVA. Nella consulenza IT, \u0026ldquo;lavorare a partita IVA\u0026rdquo; significa operare come libero professionista, fatturando i propri servizi direttamente al cliente.\nCome funziona #Il consulente a partita IVA emette fattura al cliente al termine del periodo di lavoro. Il pagamento avviene secondo i termini contrattuali — che in Italia sono tipicamente 60-90-120 giorni fine mese. Nel frattempo, il consulente sostiene tutte le spese (contributi INPS, tasse, affitto, utenze) con liquidità propria.\nA cosa serve #È il regime standard per la consulenza IT in Italia. Offre flessibilità e autonomia, ma espone il professionista al rischio di credito: se il cliente non paga o paga in ritardo, il consulente non ha tutele paragonabili a quelle di un dipendente. Non c\u0026rsquo;è cassa integrazione, non c\u0026rsquo;è TFR, non c\u0026rsquo;è tredicesima.\nCosa può andare storto #Con termini di pagamento a 90 giorni e un solo cliente, il consulente a partita IVA è l\u0026rsquo;anello più debole della catena. Non ha potere negoziale, non ha un ufficio legale, e rifiutare le condizioni significa restare senza progetti. La diversificazione dei clienti è la strategia difensiva principale.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/partita-iva/","section":"Glossario","summary":"\u003cp\u003eLa \u003cstrong\u003ePartita IVA\u003c/strong\u003e è il codice di identificazione fiscale assegnato ai lavoratori autonomi e alle imprese in Italia per le operazioni soggette a IVA. Nella consulenza IT, \u0026ldquo;lavorare a partita IVA\u0026rdquo; significa operare come libero professionista, fatturando i propri servizi direttamente al cliente.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl consulente a partita IVA emette fattura al cliente al termine del periodo di lavoro. Il pagamento avviene secondo i termini contrattuali — che in Italia sono tipicamente 60-90-120 giorni fine mese. Nel frattempo, il consulente sostiene tutte le spese (contributi INPS, tasse, affitto, utenze) con liquidità propria.\u003c/p\u003e","title":"Partita IVA"},{"content":"Il Partition Pruning è il meccanismo con cui Oracle, durante l\u0026rsquo;esecuzione di una query su una tabella partizionata, identifica ed esclude automaticamente le partizioni che non possono contenere dati rilevanti per il predicato della query.\nCome funziona #Quando una query include un predicato sulla colonna di partizione (es. WHERE data_movimento BETWEEN ...), Oracle consulta i metadati delle partizioni e determina quali partizioni contengono dati nell\u0026rsquo;intervallo richiesto. Solo quelle partizioni vengono lette. Nel piano di esecuzione appare come PARTITION RANGE SINGLE o PARTITION RANGE ITERATOR.\nA cosa serve #Su una tabella da 380 GB con partizioni mensili, una query su un singolo mese legge solo ~4 GB invece dell\u0026rsquo;intera tabella. Il pruning trasforma un full table scan da incubo in un full partition scan gestibile, riducendo I/O del 99%.\nQuando si usa #Il pruning è automatico, ma funziona solo con predicati diretti sulla colonna di partizione. Applicare funzioni alla colonna (TRUNC(data), TO_CHAR(data)) disabilita il pruning e forza Oracle a leggere tutte le partizioni. Verificare sempre con EXPLAIN PLAN che il pruning sia attivo.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/partition-pruning/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003ePartition Pruning\u003c/strong\u003e è il meccanismo con cui Oracle, durante l\u0026rsquo;esecuzione di una query su una tabella partizionata, identifica ed esclude automaticamente le partizioni che non possono contenere dati rilevanti per il predicato della query.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando una query include un predicato sulla colonna di partizione (es. \u003ccode\u003eWHERE data_movimento BETWEEN ...\u003c/code\u003e), Oracle consulta i metadati delle partizioni e determina quali partizioni contengono dati nell\u0026rsquo;intervallo richiesto. Solo quelle partizioni vengono lette. Nel piano di esecuzione appare come \u003ccode\u003ePARTITION RANGE SINGLE\u003c/code\u003e o \u003ccode\u003ePARTITION RANGE ITERATOR\u003c/code\u003e.\u003c/p\u003e","title":"Partition Pruning"},{"content":"La Pedalata Assistita è un sistema di propulsione elettrica montato su una bicicletta che amplifica la forza della pedalata del ciclista tramite un motore elettrico. Il motore si attiva solo quando si pedala e si disattiva sopra i 25 km/h (limite europeo).\nCome funziona #Un sensore rileva la forza e la cadenza della pedalata e attiva il motore elettrico proporzionalmente. Più pedali forte, più il motore aiuta. Il risultato è che salite come il Celio a Roma diventano un leggero dosso, e si arriva a destinazione senza sudare — un dettaglio cruciale per chi deve presentarsi in ufficio.\nA cosa serve #Elimina le due obiezioni principali alla bicicletta come mezzo di trasporto urbano: le salite e il sudore. Con la pedalata assistita, un percorso di 8 km in città si copre in 18 minuti indipendentemente dal dislivello, arrivando freschi e pronti a lavorare. L\u0026rsquo;autonomia tipica è di 40-80 km, più che sufficiente per una settimana di pendolarismo.\nPerché è critico #Con l\u0026rsquo;e-bike, l\u0026rsquo;argomento \u0026ldquo;Roma ha i sette colli\u0026rdquo; cade. I sette colli non esistono più con un motore che assiste in salita. Questo rende la bicicletta competitiva con l\u0026rsquo;auto anche in città collinari, eliminando l\u0026rsquo;ultima scusa per restare nel traffico.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/pedalata-assistita/","section":"Glossario","summary":"\u003cp\u003eLa \u003cstrong\u003ePedalata Assistita\u003c/strong\u003e è un sistema di propulsione elettrica montato su una bicicletta che amplifica la forza della pedalata del ciclista tramite un motore elettrico. Il motore si attiva solo quando si pedala e si disattiva sopra i 25 km/h (limite europeo).\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn sensore rileva la forza e la cadenza della pedalata e attiva il motore elettrico proporzionalmente. Più pedali forte, più il motore aiuta. Il risultato è che salite come il Celio a Roma diventano un leggero dosso, e si arriva a destinazione senza sudare — un dettaglio cruciale per chi deve presentarsi in ufficio.\u003c/p\u003e","title":"Pedalata Assistita"},{"content":"Il Pendolarismo (commuting) è lo spostamento quotidiano tra casa e luogo di lavoro. Nelle grandi città italiane come Roma, il pendolarismo medio assorbe 2-4 ore al giorno, con costi diretti (carburante, parcheggio, mezzi pubblici) e indiretti (stress, stanchezza, produttività persa).\nCome funziona #Un consulente IT che vive a 30 km dall\u0026rsquo;ufficio a Roma può impiegare 1h15-2h30 solo per l\u0026rsquo;andata. Su 220 giorni lavorativi, sono 47-89 ore perse al mese — fino a due settimane lavorative passate in auto senza produrre nulla.\nPerché è critico #Il pendolarismo non è solo tempo perso. È energia mentale bruciata prima di iniziare a lavorare. Un consulente IT lavora con la testa: analizza sistemi, scrive codice, progetta architetture. Se quella testa arriva già scarica dopo un\u0026rsquo;ora di traffico, il valore della giornata lavorativa è compromesso in partenza.\nCosa può andare storto #Le aziende che ignorano il costo del pendolarismo pagano un prezzo nascosto: per 50 consulenti a Roma, il costo stimato è di ~1.700.000 euro/anno tra ore perse, affitti ufficio e spese correlate. Lo smart working all'80% riduce questo costo a ~174.000 euro/anno dal secondo anno.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/pendolarismo/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003ePendolarismo\u003c/strong\u003e (commuting) è lo spostamento quotidiano tra casa e luogo di lavoro. Nelle grandi città italiane come Roma, il pendolarismo medio assorbe 2-4 ore al giorno, con costi diretti (carburante, parcheggio, mezzi pubblici) e indiretti (stress, stanchezza, produttività persa).\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn consulente IT che vive a 30 km dall\u0026rsquo;ufficio a Roma può impiegare 1h15-2h30 solo per l\u0026rsquo;andata. Su 220 giorni lavorativi, sono 47-89 ore perse al mese — fino a due settimane lavorative passate in auto senza produrre nulla.\u003c/p\u003e","title":"Pendolarismo"},{"content":"pg_stat_statements è un\u0026rsquo;estensione di PostgreSQL — inclusa nella distribuzione ufficiale ma non attiva di default — che tiene traccia delle statistiche di esecuzione di tutte le query SQL che passano dal server. Le query vengono normalizzate (i valori letterali sostituiti con parametri) per raggruppare le esecuzioni dello stesso pattern.\nCome funziona #L\u0026rsquo;estensione richiede di essere caricata come shared library all\u0026rsquo;avvio del server tramite il parametro shared_preload_libraries. Una volta attiva, registra per ogni query: numero di esecuzioni, tempo totale e medio, righe restituite, blocchi letti da disco e da cache. Il parametro pg_stat_statements.max controlla quante query distinte vengono tracciate (default 5000).\nA cosa serve #È lo strumento principale per identificare le query più costose su un server PostgreSQL. Ordinando per total_exec_time si ottiene immediatamente la classifica delle query che consumano più risorse. Combinato con EXPLAIN ANALYZE, permette un workflow diagnostico completo: pg_stat_statements identifica il problema, EXPLAIN spiega la causa.\nQuando si usa #Dovrebbe essere attivo su qualsiasi installazione PostgreSQL di produzione. L\u0026rsquo;overhead è trascurabile (1-2% di CPU). Senza pg_stat_statements, qualsiasi attività di performance tuning si basa su ipotesi anziché su dati.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/pg-stat-statements/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003epg_stat_statements\u003c/strong\u003e è un\u0026rsquo;estensione di PostgreSQL — inclusa nella distribuzione ufficiale ma non attiva di default — che tiene traccia delle statistiche di esecuzione di tutte le query SQL che passano dal server. Le query vengono normalizzate (i valori letterali sostituiti con parametri) per raggruppare le esecuzioni dello stesso pattern.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eL\u0026rsquo;estensione richiede di essere caricata come shared library all\u0026rsquo;avvio del server tramite il parametro \u003ccode\u003eshared_preload_libraries\u003c/code\u003e. Una volta attiva, registra per ogni query: numero di esecuzioni, tempo totale e medio, righe restituite, blocchi letti da disco e da cache. Il parametro \u003ccode\u003epg_stat_statements.max\u003c/code\u003e controlla quante query distinte vengono tracciate (default 5000).\u003c/p\u003e","title":"pg_stat_statements"},{"content":"pg_trgm è un\u0026rsquo;estensione di PostgreSQL che implementa la ricerca basata su trigrammi — sequenze di tre caratteri consecutivi estratte dal testo. Abilita l\u0026rsquo;uso di indici GIN e GiST per accelerare ricerche LIKE '%valore%' e ILIKE, che altrimenti richiederebbero scansioni sequenziali.\nCome funziona #L\u0026rsquo;estensione scompone ogni stringa in trigrammi: ad esempio, \u0026ldquo;hello\u0026rdquo; diventa {\u0026quot; h\u0026quot;, \u0026quot; he\u0026quot;, \u0026ldquo;hel\u0026rdquo;, \u0026ldquo;ell\u0026rdquo;, \u0026ldquo;llo\u0026rdquo;, \u0026ldquo;lo \u0026ldquo;}. Un indice GIN con operator class gin_trgm_ops indicizza questi trigrammi. Quando si esegue un LIKE '%ell%', PostgreSQL cerca i trigrammi corrispondenti nell\u0026rsquo;indice invece di scansionare l\u0026rsquo;intera tabella.\nA cosa serve #pg_trgm risolve uno dei problemi più comuni in PostgreSQL: la ricerca \u0026ldquo;contiene\u0026rdquo; su colonne di testo grandi. Senza pg_trgm, un LIKE '%valore%' su una tabella di milioni di righe richiede una scansione completa. Con pg_trgm e un indice GIN, la stessa ricerca usa l\u0026rsquo;indice e risponde in millisecondi.\nQuando si usa #Si attiva con CREATE EXTENSION IF NOT EXISTS pg_trgm e si crea l\u0026rsquo;indice con USING gin (colonna gin_trgm_ops). È ideale su tabelle con basso churn (pochi UPDATE/DELETE). La creazione dell\u0026rsquo;indice va fatta con CONCURRENTLY in produzione per evitare lock.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/pg-trgm/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003epg_trgm\u003c/strong\u003e è un\u0026rsquo;estensione di PostgreSQL che implementa la ricerca basata su trigrammi — sequenze di tre caratteri consecutivi estratte dal testo. Abilita l\u0026rsquo;uso di indici GIN e GiST per accelerare ricerche \u003ccode\u003eLIKE '%valore%'\u003c/code\u003e e \u003ccode\u003eILIKE\u003c/code\u003e, che altrimenti richiederebbero scansioni sequenziali.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eL\u0026rsquo;estensione scompone ogni stringa in trigrammi: ad esempio, \u0026ldquo;hello\u0026rdquo; diventa {\u0026quot;  h\u0026quot;, \u0026quot; he\u0026quot;, \u0026ldquo;hel\u0026rdquo;, \u0026ldquo;ell\u0026rdquo;, \u0026ldquo;llo\u0026rdquo;, \u0026ldquo;lo \u0026ldquo;}. Un indice GIN con operator class \u003ccode\u003egin_trgm_ops\u003c/code\u003e indicizza questi trigrammi. Quando si esegue un \u003ccode\u003eLIKE '%ell%'\u003c/code\u003e, PostgreSQL cerca i trigrammi corrispondenti nell\u0026rsquo;indice invece di scansionare l\u0026rsquo;intera tabella.\u003c/p\u003e","title":"pg_trgm"},{"content":"PITR (Point-in-Time Recovery) è una tecnica di ripristino che permette di riportare un database a un qualsiasi momento nel tempo, non solo al momento del backup. Si basa sulla combinazione di un backup completo e dei log delle transazioni (binary log in MySQL, WAL in PostgreSQL, redo log in Oracle).\nCome funziona #Il processo si articola in due fasi:\nRestore del backup: si ripristina il database all\u0026rsquo;ultimo backup disponibile Replay dei log: si riapplicano i log delle transazioni dal momento del backup fino al momento desiderato, escludendo l\u0026rsquo;evento che ha causato il problema In MySQL, il tool mysqlbinlog estrae gli eventi dai binary log e li riproduce sul database ripristinato.\nA cosa serve #PITR è essenziale quando si verifica un errore umano (DROP TABLE, DELETE senza WHERE, UPDATE massivo sbagliato) e si deve ripristinare il database allo stato immediatamente precedente all\u0026rsquo;errore, senza perdere le ore di lavoro tra l\u0026rsquo;ultimo backup e l\u0026rsquo;incidente.\nQuando si usa #PITR richiede che il binary log sia attivo e che i file binlog non siano stati eliminati. La retention dei binlog deve coprire almeno il doppio dell\u0026rsquo;intervallo tra due backup consecutivi per garantire una copertura PITR completa.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/pitr/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003ePITR\u003c/strong\u003e (Point-in-Time Recovery) è una tecnica di ripristino che permette di riportare un database a un qualsiasi momento nel tempo, non solo al momento del backup. Si basa sulla combinazione di un backup completo e dei log delle transazioni (binary log in MySQL, WAL in PostgreSQL, redo log in Oracle).\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl processo si articola in due fasi:\u003c/p\u003e","title":"PITR"},{"content":"Il Presenteismo è la cultura organizzativa che misura il valore del lavoro in base alla presenza fisica del dipendente in ufficio, indipendentemente dalla qualità e quantità dei risultati prodotti. È il presupposto che \u0026ldquo;se ti vedo alla scrivania, stai lavorando.\u0026rdquo;\nCome funziona #In un\u0026rsquo;organizzazione presenteista, essere in ufficio dalle 9 alle 18 è più importante di chiudere i task. Arrivare tardi è un problema anche se hai prodotto più di tutti. Lavorare da casa è sospetto anche se i risultati sono eccellenti. Il controllo si basa sulla vista, non sulle metriche.\nPerché è critico #Il presenteismo è il principale ostacolo all\u0026rsquo;adozione dello smart working nella consulenza IT. Un consulente informatico non lavora in catena di montaggio — ha bisogno di concentrazione, silenzio e strumenti digitali, non di una scrivania in un open space rumoroso. Confondere presenza con produttività è un retaggio culturale, non una necessità operativa.\nCosa può andare storto #Le aziende che non superano il presenteismo pagano un costo invisibile: ore di pendolarismo non produttive, dipendenti che arrivano stressati e scarichi, talenti che se ne vanno verso aziende più flessibili. Il presenteismo non protegge la produttività — la distrugge.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/presenteismo/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003ePresenteismo\u003c/strong\u003e è la cultura organizzativa che misura il valore del lavoro in base alla presenza fisica del dipendente in ufficio, indipendentemente dalla qualità e quantità dei risultati prodotti. È il presupposto che \u0026ldquo;se ti vedo alla scrivania, stai lavorando.\u0026rdquo;\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIn un\u0026rsquo;organizzazione presenteista, essere in ufficio dalle 9 alle 18 è più importante di chiudere i task. Arrivare tardi è un problema anche se hai prodotto più di tutti. Lavorare da casa è sospetto anche se i risultati sono eccellenti. Il controllo si basa sulla vista, non sulle metriche.\u003c/p\u003e","title":"Presenteismo"},{"content":"Una Pull Request (PR) è una richiesta formale di incorporare le modifiche da un branch di sviluppo nel branch principale del repository. È il meccanismo centrale di collaborazione su GitHub e piattaforme simili.\nCome funziona #Lo sviluppatore lavora su un branch dedicato (es. fix/issue-234-errore-calcolo), completa le modifiche, e apre una PR. La PR mostra il diff del codice, permette ai colleghi di commentare riga per riga, richiedere modifiche o approvare. Solo dopo l\u0026rsquo;approvazione il codice viene unito (merged) nel branch principale. Questo garantisce che il codice \u0026ldquo;buono\u0026rdquo; resti sempre buono.\nA cosa serve #La PR trasforma lo sviluppo da un\u0026rsquo;attività individuale a un processo di team. Previene sovrascritture accidentali, cattura bug prima che arrivino in produzione, e crea una cronologia completa di chi ha fatto cosa, quando e perché. In progetti caotici, è la differenza tra controllo e disordine.\nQuando si usa #Su ogni modifica al codice, senza eccezioni. Anche le correzioni piccole passano per una PR, perché il valore non è solo nella review ma nella tracciabilità. Su piattaforme GitLab la stessa funzionalità si chiama Merge Request.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/pull-request/","section":"Glossario","summary":"\u003cp\u003eUna \u003cstrong\u003ePull Request\u003c/strong\u003e (PR) è una richiesta formale di incorporare le modifiche da un branch di sviluppo nel branch principale del repository. È il meccanismo centrale di collaborazione su GitHub e piattaforme simili.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLo sviluppatore lavora su un branch dedicato (es. \u003ccode\u003efix/issue-234-errore-calcolo\u003c/code\u003e), completa le modifiche, e apre una PR. La PR mostra il diff del codice, permette ai colleghi di commentare riga per riga, richiedere modifiche o approvare. Solo dopo l\u0026rsquo;approvazione il codice viene unito (merged) nel branch principale. Questo garantisce che il codice \u0026ldquo;buono\u0026rdquo; resti sempre buono.\u003c/p\u003e","title":"Pull Request"},{"content":"Il quorum è il numero minimo di nodi che devono essere d\u0026rsquo;accordo per considerare il cluster operativo. In un cluster a 3 nodi, il quorum è 2 (la maggioranza). Se un nodo si disconnette, gli altri due riconoscono di essere la maggioranza e continuano a operare normalmente.\nCome funziona #Galera Cluster utilizza un protocollo di comunicazione di gruppo che verifica continuamente quanti nodi sono raggiungibili. Il calcolo è semplice: quorum = (numero totale nodi / 2) + 1. Con 3 nodi il quorum è 2, con 5 nodi è 3. I nodi che perdono il quorum passano allo stato Non-Primary e rifiutano le scritture per evitare inconsistenze.\nA cosa serve #Il quorum previene lo split-brain: la situazione in cui due parti del cluster operano indipendentemente, accettando scritture diverse sugli stessi dati. Senza quorum, un\u0026rsquo;interruzione di rete potrebbe portare a dati divergenti impossibili da riconciliare automaticamente.\nQuando si usa #Il quorum è attivo automaticamente in qualsiasi cluster Galera. Per questo motivo, tre nodi è il minimo in produzione: con due nodi, la perdita di uno lascia il superstite senza quorum e quindi bloccato.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/quorum/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003equorum\u003c/strong\u003e è il numero minimo di nodi che devono essere d\u0026rsquo;accordo per considerare il cluster operativo. In un cluster a 3 nodi, il quorum è 2 (la maggioranza). Se un nodo si disconnette, gli altri due riconoscono di essere la maggioranza e continuano a operare normalmente.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eGalera Cluster utilizza un protocollo di comunicazione di gruppo che verifica continuamente quanti nodi sono raggiungibili. Il calcolo è semplice: quorum = (numero totale nodi / 2) + 1. Con 3 nodi il quorum è 2, con 5 nodi è 3. I nodi che perdono il quorum passano allo stato Non-Primary e rifiutano le scritture per evitare inconsistenze.\u003c/p\u003e","title":"Quorum"},{"content":"RAC (Real Application Clusters) è la tecnologia Oracle che consente a più istanze del database di accedere contemporaneamente allo stesso storage condiviso. Se un nodo si guasta, gli altri continuano a servire le richieste senza interruzione — il failover è trasparente per le applicazioni.\nCome funziona #Un cluster RAC è composto da due o più server (nodi) collegati tra loro da una rete privata ad alta velocità (interconnect) e da uno storage condiviso (tipicamente ASM — Automatic Storage Management). Ogni nodo esegue la propria istanza Oracle, ma tutti accedono agli stessi datafile.\nIl protocollo Cache Fusion gestisce la coerenza dei dati tra i nodi: quando un blocco modificato da un nodo serve a un altro, viene trasferito direttamente via interconnect senza passare dal disco.\nAlta disponibilità #Se un nodo va giù, le sessioni attive vengono automaticamente trasferite ai nodi rimanenti tramite TAF (Transparent Application Failover) o Application Continuity. Il tempo di failover dipende dalla configurazione, ma tipicamente è dell\u0026rsquo;ordine di secondi.\nImplicazioni di licensing #RAC è un\u0026rsquo;opzione della Enterprise Edition e ha un costo di licensing significativo. In fase di migrazione cloud, il conteggio delle licenze RAC è uno degli aspetti più delicati: su OCI con BYOL le licenze on-premises vengono riutilizzate, su altri cloud provider il costo può moltiplicarsi.\nQuando serve davvero #RAC è giustificato quando servono alta disponibilità con failover automatico e scalabilità orizzontale. Per ambienti con pochi utenti o requisiti di uptime standard, un singolo nodo con Data Guard è spesso una soluzione più semplice e meno costosa.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/rac/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eRAC\u003c/strong\u003e (Real Application Clusters) è la tecnologia Oracle che consente a più istanze del database di accedere contemporaneamente allo stesso storage condiviso. Se un nodo si guasta, gli altri continuano a servire le richieste senza interruzione — il failover è trasparente per le applicazioni.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUn cluster RAC è composto da due o più server (nodi) collegati tra loro da una rete privata ad alta velocità (interconnect) e da uno storage condiviso (tipicamente ASM — Automatic Storage Management). Ogni nodo esegue la propria istanza Oracle, ma tutti accedono agli stessi datafile.\u003c/p\u003e","title":"RAC"},{"content":"Una ragged hierarchy (gerarchia sbilanciata) è una struttura gerarchica in cui non tutti i rami raggiungono la stessa profondità. Alcuni livelli intermedi sono assenti per determinate entità.\nEsempio concreto #In una gerarchia a tre livelli Top Group → Group → Client:\nAlcuni clienti hanno tutti e tre i livelli (gerarchia completa) Alcuni clienti hanno un Group ma nessun Top Group Alcuni clienti non hanno né Group né Top Group (clienti diretti) Il risultato è una struttura con \u0026ldquo;buchi\u0026rdquo; che causa problemi nei report di aggregazione: righe con NULL, totali spezzati, drill-down incompleti.\nPerché è un problema nel DWH #I tool di BI e le query SQL si aspettano gerarchie complete per funzionare correttamente. Un GROUP BY su una colonna con NULL produce risultati inattesi: le righe con NULL vengono raggruppate separatamente, i totali non tornano, e lo stesso gruppo può apparire su più righe.\nCome si risolve #La tecnica standard è il self-parenting: chi non ha un padre diventa padre di sé stesso. Questo bilancia la gerarchia a monte, nell\u0026rsquo;ETL, eliminando i NULL dalla tabella dimensionale. Flag aggiuntivi (is_direct_client, is_standalone_group) permettono di distinguere le entità bilanciate artificialmente da quelle con gerarchia naturale.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/ragged-hierarchy/","section":"Glossario","summary":"\u003cp\u003eUna \u003cstrong\u003eragged hierarchy\u003c/strong\u003e (gerarchia sbilanciata) è una struttura gerarchica in cui non tutti i rami raggiungono la stessa profondità. Alcuni livelli intermedi sono assenti per determinate entità.\u003c/p\u003e\n\u003ch2 id=\"esempio-concreto\" class=\"relative group\"\u003eEsempio concreto \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#esempio-concreto\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIn una gerarchia a tre livelli Top Group → Group → Client:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAlcuni clienti hanno tutti e tre i livelli (gerarchia completa)\u003c/li\u003e\n\u003cli\u003eAlcuni clienti hanno un Group ma nessun Top Group\u003c/li\u003e\n\u003cli\u003eAlcuni clienti non hanno né Group né Top Group (clienti diretti)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIl risultato è una struttura con \u0026ldquo;buchi\u0026rdquo; che causa problemi nei report di aggregazione: righe con NULL, totali spezzati, drill-down incompleti.\u003c/p\u003e","title":"Ragged hierarchy"},{"content":"Il Range Partitioning (partizionamento per intervallo) è una strategia di partizionamento delle tabelle in cui le righe vengono distribuite in partizioni diverse in base al valore di una colonna rispetto a intervalli predefiniti. La colonna di partizionamento è quasi sempre una data nei data warehouse.\nCome funziona #Ogni partizione è definita con una clausola VALUES LESS THAN che stabilisce il limite superiore dell\u0026rsquo;intervallo. Oracle assegna automaticamente ogni riga alla partizione corretta in base al valore della colonna di partizionamento. Se una riga ha data_vendita = '2025-03-15', viene inserita nella partizione il cui intervallo include quella data.\nQuando si usa #Il range partitioning è la scelta naturale quando i dati hanno una dimensione temporale dominante — fact table nei data warehouse, tabelle di log, tabelle di transazioni. La granularità della partizione (giornaliera, mensile, trimestrale) dipende dal volume di inserimento e dalla tipologia delle query: partizioni troppo piccole generano overhead di gestione, troppo grandi riducono l\u0026rsquo;efficacia del partition pruning.\nVantaggi operativi #Oltre alle performance delle query, il range partitioning abilita operazioni di gestione del ciclo di vita dei dati impossibili su tabelle monolitiche: drop istantaneo di una partizione (senza DELETE), compressione selettiva delle partizioni storiche, spostamento su storage diversi (ILM — Information Lifecycle Management), e exchange partition per caricamenti bulk a impatto zero.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/range-partitioning/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eRange Partitioning\u003c/strong\u003e (partizionamento per intervallo) è una strategia di partizionamento delle tabelle in cui le righe vengono distribuite in partizioni diverse in base al valore di una colonna rispetto a intervalli predefiniti. La colonna di partizionamento è quasi sempre una data nei data warehouse.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOgni partizione è definita con una clausola \u003ccode\u003eVALUES LESS THAN\u003c/code\u003e che stabilisce il limite superiore dell\u0026rsquo;intervallo. Oracle assegna automaticamente ogni riga alla partizione corretta in base al valore della colonna di partizionamento. Se una riga ha \u003ccode\u003edata_vendita = '2025-03-15'\u003c/code\u003e, viene inserita nella partizione il cui intervallo include quella data.\u003c/p\u003e","title":"Range Partitioning"},{"content":"Redo Log è il meccanismo con cui Oracle registra ogni modifica ai dati del database (INSERT, UPDATE, DELETE, DDL) prima che venga scritta definitivamente nei datafile. È la garanzia fondamentale di durabilità delle transazioni.\nCome funziona #Oracle scrive le modifiche nei redo log online in modo sequenziale e continuo. I redo log sono organizzati in gruppi circolari: quando un gruppo si riempie, Oracle passa al successivo. Quando tutti i gruppi sono stati usati, Oracle torna al primo (log switch).\nOnline vs Archived # Online redo log: i file attivi dove Oracle scrive in tempo reale. Sono circolari e si sovrascrivono Archived redo log: copie dei redo log online salvate prima della sovrascrittura. Necessari per il recovery point-in-time e per Data Guard La modalità ARCHIVELOG del database attiva la creazione automatica degli archived log. Senza di essa, i redo vengono sovrascritti e il recovery è limitato all\u0026rsquo;ultimo backup completo.\nPerché sono importanti #I redo log sono il cuore del recovery e della replica Oracle. Senza redo:\nNon è possibile il recovery dopo un crash (instance recovery) Non è possibile il recovery point-in-time (media recovery) Data Guard non può funzionare (la replica si basa interamente sui redo) Non è possibile il flashback database ","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/redo-log/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eRedo Log\u003c/strong\u003e è il meccanismo con cui Oracle registra ogni modifica ai dati del database (INSERT, UPDATE, DELETE, DDL) prima che venga scritta definitivamente nei datafile. È la garanzia fondamentale di durabilità delle transazioni.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOracle scrive le modifiche nei redo log online in modo sequenziale e continuo. I redo log sono organizzati in gruppi circolari: quando un gruppo si riempie, Oracle passa al successivo. Quando tutti i gruppi sono stati usati, Oracle torna al primo (log switch).\u003c/p\u003e","title":"Redo Log"},{"content":"Il relay log è un file di log intermedio presente sullo slave in un\u0026rsquo;architettura di replica MySQL. Contiene gli eventi ricevuti dal binary log del master, in attesa di essere eseguiti localmente dal thread SQL dello slave.\nCome funziona #Il flusso della replica MySQL passa attraverso il relay log in tre fasi:\nL\u0026rsquo;I/O thread dello slave si connette al master e legge i binary log Gli eventi ricevuti vengono scritti nel relay log locale Il SQL thread dello slave legge gli eventi dal relay log e li esegue sul database locale Questa architettura a due thread permette di disaccoppiare la ricezione dei dati dalla loro applicazione: lo slave può continuare a ricevere eventi dal master anche se l\u0026rsquo;esecuzione locale è temporaneamente rallentata.\nA cosa serve #Il relay log è il meccanismo che garantisce la consistenza della replica. Funge da buffer tra il master e l\u0026rsquo;applicazione locale degli eventi, permettendo allo slave di gestire eventuali differenze di velocità senza perdere dati.\nQuando si usa #Il relay log viene creato automaticamente quando si configura una replica MySQL. Non richiede gestione manuale diretta, ma il suo stato (posizione corrente, eventuale ritardo) è visibile tramite SHOW REPLICA STATUS ed è fondamentale per diagnosticare problemi di replica lag.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/relay-log/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003erelay log\u003c/strong\u003e è un file di log intermedio presente sullo slave in un\u0026rsquo;architettura di replica MySQL. Contiene gli eventi ricevuti dal binary log del master, in attesa di essere eseguiti localmente dal thread SQL dello slave.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl flusso della replica MySQL passa attraverso il relay log in tre fasi:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eL\u0026rsquo;\u003cstrong\u003eI/O thread\u003c/strong\u003e dello slave si connette al master e legge i binary log\u003c/li\u003e\n\u003cli\u003eGli eventi ricevuti vengono scritti nel relay log locale\u003c/li\u003e\n\u003cli\u003eIl \u003cstrong\u003eSQL thread\u003c/strong\u003e dello slave legge gli eventi dal relay log e li esegue sul database locale\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eQuesta architettura a due thread permette di disaccoppiare la ricezione dei dati dalla loro applicazione: lo slave può continuare a ricevere eventi dal master anche se l\u0026rsquo;esecuzione locale è temporaneamente rallentata.\u003c/p\u003e","title":"Relay log"},{"content":"REVOKE è il comando SQL che rimuove privilegi o ruoli precedentemente assegnati con GRANT. È il complemento indispensabile del GRANT e lo strumento principale per restringere i permessi quando un modello di sicurezza viene ristrutturato.\nCome funziona #La sintassi segue lo stesso schema del GRANT: REVOKE SELECT ON schema.tabella FROM utente oppure REVOKE ruolo FROM utente. In Oracle, revocare un ruolo come DBA rimuove in un colpo solo tutti i system privileges inclusi in quel ruolo. Prima di eseguire un REVOKE critico, è fondamentale verificare che l\u0026rsquo;utente mantenga i privilegi necessari per le sue funzioni.\nQuando si usa #Il caso più comune è la ristrutturazione del modello di sicurezza: rimuovere ruoli eccessivi (come DBA da utenti applicativi) e sostituirli con ruoli custom calibrati. Si usa anche quando un utente cambia funzione, quando un servizio viene dismesso, o quando un audit rivela privilegi assegnati in eccesso.\nCosa può andare storto #Un REVOKE mal pianificato può bloccare applicazioni in produzione. Se un\u0026rsquo;applicazione si connette con un utente che perde il privilegio CREATE SESSION, smette di funzionare istantaneamente. Per questo la revoca di privilegi critici va sempre preceduta da un\u0026rsquo;analisi delle dipendenze e da un piano di rollout graduale.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/revoke/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eREVOKE\u003c/strong\u003e è il comando SQL che rimuove privilegi o ruoli precedentemente assegnati con \u003ccode\u003eGRANT\u003c/code\u003e. È il complemento indispensabile del GRANT e lo strumento principale per restringere i permessi quando un modello di sicurezza viene ristrutturato.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa sintassi segue lo stesso schema del GRANT: \u003ccode\u003eREVOKE SELECT ON schema.tabella FROM utente\u003c/code\u003e oppure \u003ccode\u003eREVOKE ruolo FROM utente\u003c/code\u003e. In Oracle, revocare un ruolo come \u003ccode\u003eDBA\u003c/code\u003e rimuove in un colpo solo tutti i system privileges inclusi in quel ruolo. Prima di eseguire un REVOKE critico, è fondamentale verificare che l\u0026rsquo;utente mantenga i privilegi necessari per le sue funzioni.\u003c/p\u003e","title":"REVOKE"},{"content":"RMAN (Recovery Manager) è lo strumento nativo di Oracle per il backup, il restore e il recovery del database. È un\u0026rsquo;utility a riga di comando che gestisce tutte le operazioni di protezione dei dati in modo integrato con il database.\nCosa fa # Backup: completi, incrementali, dei soli archived log Restore: ripristino di datafile, tablespace o dell\u0026rsquo;intero database Recovery: applicazione dei redo log per portare il database a un punto nel tempo specifico Duplicate: creazione di copie del database, inclusi database standby per Data Guard RMAN e Data Guard #Per la creazione di un database standby, RMAN permette il DUPLICATE ... FOR STANDBY FROM ACTIVE DATABASE — una copia diretta via rete dal primario allo standby, senza bisogno di backup intermedi su nastro o disco. Il comando trasferisce tutti i datafile, i controlfile e li configura automaticamente per la replica.\nPerché RMAN e non copie manuali #RMAN conosce la struttura interna del database Oracle: sa quali blocchi sono cambiati (per gli incrementali), quali file servono, come applicare i redo. Una copia manuale dei file (con cp o rsync) non garantisce la consistenza e richiede che il database sia chiuso. RMAN può lavorare a database aperto, con impatto minimo sulle performance.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/rman/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eRMAN\u003c/strong\u003e (Recovery Manager) è lo strumento nativo di Oracle per il backup, il restore e il recovery del database. È un\u0026rsquo;utility a riga di comando che gestisce tutte le operazioni di protezione dei dati in modo integrato con il database.\u003c/p\u003e\n\u003ch2 id=\"cosa-fa\" class=\"relative group\"\u003eCosa fa \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#cosa-fa\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eBackup\u003c/strong\u003e: completi, incrementali, dei soli archived log\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRestore\u003c/strong\u003e: ripristino di datafile, tablespace o dell\u0026rsquo;intero database\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRecovery\u003c/strong\u003e: applicazione dei redo log per portare il database a un punto nel tempo specifico\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDuplicate\u003c/strong\u003e: creazione di copie del database, inclusi database standby per Data Guard\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"rman-e-data-guard\" class=\"relative group\"\u003eRMAN e Data Guard \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#rman-e-data-guard\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003ePer la creazione di un database standby, RMAN permette il \u003ccode\u003eDUPLICATE ... FOR STANDBY FROM ACTIVE DATABASE\u003c/code\u003e — una copia diretta via rete dal primario allo standby, senza bisogno di backup intermedi su nastro o disco. Il comando trasferisce tutti i datafile, i controlfile e li configura automaticamente per la replica.\u003c/p\u003e","title":"RMAN"},{"content":"Il ROI (Return on Investment) è la metrica che misura il rendimento di un investimento rapportando il beneficio netto al costo sostenuto, espresso come percentuale. Un ROI del 200% significa che ogni euro investito ne ha generati due di ritorno.\nCome funziona #Si calcola come: (Beneficio - Costo) / Costo × 100. Nel contesto dei progetti IT con componenti AI, il calcolo del ROI deve includere non solo i costi di implementazione ma anche quelli di manutenzione, training del team, governance e gestione degli errori del modello.\nA cosa serve #Il ROI è lo strumento principale per valutare se un investimento in AI ha senso economico. Ma nel mercato attuale è anche lo strumento più abusato: vendor che promettono ROI a tre cifre basandosi su demo controllate, senza considerare i costi operativi reali. L\u0026rsquo;AI Manager è chi verifica che i numeri siano reali, non da slide.\nCosa può andare storto #Un ROI calcolato solo sui benefici immediati senza contare i costi nascosti (manutenzione del modello, retraining periodico, gestione dei falsi positivi, compliance GDPR) è un ROI falso. La differenza tra un progetto AI di successo e un fallimento costoso sta quasi sempre nella qualità del calcolo del ROI iniziale.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/roi/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eROI\u003c/strong\u003e (Return on Investment) è la metrica che misura il rendimento di un investimento rapportando il beneficio netto al costo sostenuto, espresso come percentuale. Un ROI del 200% significa che ogni euro investito ne ha generati due di ritorno.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSi calcola come: \u003ccode\u003e(Beneficio - Costo) / Costo × 100\u003c/code\u003e. Nel contesto dei progetti IT con componenti AI, il calcolo del ROI deve includere non solo i costi di implementazione ma anche quelli di manutenzione, training del team, governance e gestione degli errori del modello.\u003c/p\u003e","title":"ROI"},{"content":"In PostgreSQL, ROLE è l\u0026rsquo;unica entità di sicurezza. Non esiste una distinzione tra \u0026ldquo;utente\u0026rdquo; e \u0026ldquo;ruolo\u0026rdquo;: tutto è un ROLE. Un ROLE con l\u0026rsquo;attributo LOGIN si comporta come un utente; senza LOGIN, è un contenitore di privilegi assegnabile ad altri ROLE.\nCome funziona #CREATE USER mario è semplicemente uno shortcut per CREATE ROLE mario WITH LOGIN. I ROLE possono possedere oggetti, ereditare privilegi da altri ROLE tramite l\u0026rsquo;attributo INHERIT, e essere utilizzati per costruire gerarchie di permessi. Un ROLE \u0026ldquo;funzionale\u0026rdquo; (senza LOGIN) raggruppa i privilegi; i ROLE \u0026ldquo;utente\u0026rdquo; (con LOGIN) li ereditano.\nA cosa serve #Il modello unificato permette di progettare architetture di sicurezza pulite: si creano ROLE funzionali come role_readonly o role_write, si assegnano i privilegi ai ROLE funzionali, e poi si assegnano questi ROLE agli utenti reali. Quando arriva un nuovo collega, basta un GRANT role_readonly TO nuovo_utente.\nPerché è critico #La semplicità del modello è il suo punto di forza — ma anche una trappola se non lo si capisce. Molti amministratori assegnano privilegi direttamente agli utenti invece di usare ROLE funzionali, creando un groviglio di GRANT impossibile da manutenere. Il modello mentale corretto è: i privilegi vanno ai ROLE, i ROLE vanno agli utenti.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/postgresql-role/","section":"Glossario","summary":"\u003cp\u003eIn PostgreSQL, \u003cstrong\u003eROLE\u003c/strong\u003e è l\u0026rsquo;unica entità di sicurezza. Non esiste una distinzione tra \u0026ldquo;utente\u0026rdquo; e \u0026ldquo;ruolo\u0026rdquo;: tutto è un ROLE. Un ROLE con l\u0026rsquo;attributo \u003ccode\u003eLOGIN\u003c/code\u003e si comporta come un utente; senza \u003ccode\u003eLOGIN\u003c/code\u003e, è un contenitore di privilegi assegnabile ad altri ROLE.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003e\u003ccode\u003eCREATE USER mario\u003c/code\u003e è semplicemente uno shortcut per \u003ccode\u003eCREATE ROLE mario WITH LOGIN\u003c/code\u003e. I ROLE possono possedere oggetti, ereditare privilegi da altri ROLE tramite l\u0026rsquo;attributo \u003ccode\u003eINHERIT\u003c/code\u003e, e essere utilizzati per costruire gerarchie di permessi. Un ROLE \u0026ldquo;funzionale\u0026rdquo; (senza LOGIN) raggruppa i privilegi; i ROLE \u0026ldquo;utente\u0026rdquo; (con LOGIN) li ereditano.\u003c/p\u003e","title":"ROLE"},{"content":"RPO (Recovery Point Objective) è la quantità massima di dati che un\u0026rsquo;organizzazione può permettersi di perdere in caso di guasto o disastro. Si misura in tempo: un RPO di 1 ora significa che si accetta di perdere al massimo l\u0026rsquo;ultima ora di transazioni.\nCome si determina #L\u0026rsquo;RPO dipende dalla strategia di backup e replica:\nStrategia RPO tipico Backup notturno su nastro 12-24 ore Backup + archived log su storage remoto 1-4 ore Data Guard asincrono (MaxPerformance) Pochi secondi Data Guard sincrono (MaxAvailability) Zero RPO vs RTO #RPO e RTO sono complementari ma distinti:\nRPO: quanti dati puoi perdere (guarda indietro nel tempo) RTO: quanto tempo ci vuole per ripristinare il servizio (guarda avanti nel tempo) Un\u0026rsquo;organizzazione può avere RPO=0 (zero data loss) ma RTO=4 ore (ci vogliono 4 ore per ripartire), o viceversa.\nPerché conta #L\u0026rsquo;RPO determina l\u0026rsquo;investimento necessario in infrastruttura di replica. Passare da RPO=24 ore a RPO=0 può costare ordini di grandezza in più, ma il costo va confrontato con il valore dei dati persi — come nel caso di sei ore di polizze assicurative non emesse.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/rpo/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eRPO\u003c/strong\u003e (Recovery Point Objective) è la quantità massima di dati che un\u0026rsquo;organizzazione può permettersi di perdere in caso di guasto o disastro. Si misura in tempo: un RPO di 1 ora significa che si accetta di perdere al massimo l\u0026rsquo;ultima ora di transazioni.\u003c/p\u003e\n\u003ch2 id=\"come-si-determina\" class=\"relative group\"\u003eCome si determina \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-si-determina\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eL\u0026rsquo;RPO dipende dalla strategia di backup e replica:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eStrategia\u003c/th\u003e\n          \u003cth\u003eRPO tipico\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eBackup notturno su nastro\u003c/td\u003e\n          \u003ctd\u003e12-24 ore\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eBackup + archived log su storage remoto\u003c/td\u003e\n          \u003ctd\u003e1-4 ore\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eData Guard asincrono (MaxPerformance)\u003c/td\u003e\n          \u003ctd\u003ePochi secondi\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eData Guard sincrono (MaxAvailability)\u003c/td\u003e\n          \u003ctd\u003eZero\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"rpo-vs-rto\" class=\"relative group\"\u003eRPO vs RTO \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#rpo-vs-rto\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eRPO e RTO sono complementari ma distinti:\u003c/p\u003e","title":"RPO"},{"content":"RTO (Recovery Time Objective) è il tempo massimo accettabile per ripristinare il servizio dopo un guasto o un disastro. Si misura dal momento del guasto al momento in cui il sistema torna operativo.\nCome si determina #L\u0026rsquo;RTO dipende dalla strategia di recovery e dall\u0026rsquo;infrastruttura disponibile:\nStrategia RTO tipico Restore da backup su nastro 4-12 ore Restore da backup su disco 1-4 ore Data Guard con switchover manuale 1-5 minuti Data Guard con Fast-Start Failover 10-30 secondi RTO vs RPO # RTO: quanto tempo ci vuole per ripartire (guarda avanti) RPO: quanti dati puoi perdere (guarda indietro) Sono metriche indipendenti. Un restore da backup può avere RTO=2 ore e RPO=24 ore. Un Data Guard sincrono può avere RTO=30 secondi e RPO=0.\nL\u0026rsquo;impatto sul business #L\u0026rsquo;RTO ha un impatto diretto e misurabile: ogni minuto di fermo si traduce in operazioni bloccate, clienti non serviti, ricavi persi. La differenza tra RTO=6 ore e RTO=42 secondi — come nel caso del passaggio da single instance a Data Guard — può valere più del costo dell\u0026rsquo;intera infrastruttura.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/rto/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eRTO\u003c/strong\u003e (Recovery Time Objective) è il tempo massimo accettabile per ripristinare il servizio dopo un guasto o un disastro. Si misura dal momento del guasto al momento in cui il sistema torna operativo.\u003c/p\u003e\n\u003ch2 id=\"come-si-determina\" class=\"relative group\"\u003eCome si determina \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-si-determina\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eL\u0026rsquo;RTO dipende dalla strategia di recovery e dall\u0026rsquo;infrastruttura disponibile:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eStrategia\u003c/th\u003e\n          \u003cth\u003eRTO tipico\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eRestore da backup su nastro\u003c/td\u003e\n          \u003ctd\u003e4-12 ore\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eRestore da backup su disco\u003c/td\u003e\n          \u003ctd\u003e1-4 ore\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eData Guard con switchover manuale\u003c/td\u003e\n          \u003ctd\u003e1-5 minuti\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eData Guard con Fast-Start Failover\u003c/td\u003e\n          \u003ctd\u003e10-30 secondi\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"rto-vs-rpo\" class=\"relative group\"\u003eRTO vs RPO \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#rto-vs-rpo\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eRTO\u003c/strong\u003e: quanto tempo ci vuole per ripartire (guarda avanti)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRPO\u003c/strong\u003e: quanti dati puoi perdere (guarda indietro)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eSono metriche indipendenti. Un restore da backup può avere RTO=2 ore e RPO=24 ore. Un Data Guard sincrono può avere RTO=30 secondi e RPO=0.\u003c/p\u003e","title":"RTO"},{"content":"Lo SCAN Listener (Single Client Access Name) è il componente di Oracle RAC che fornisce un unico nome DNS per l\u0026rsquo;accesso al cluster. Le applicazioni si connettono allo SCAN name senza dover conoscere i singoli nodi: il listener distribuisce automaticamente le connessioni tra i nodi attivi.\nCome funziona #Lo SCAN è un nome DNS che risolve a tre indirizzi IP virtuali (VIP), distribuiti tra i nodi del cluster. Quando un client si connette allo SCAN name, il DNS restituisce uno dei tre IP, e il listener su quell\u0026rsquo;IP redirige la connessione al nodo più appropriato in base al servizio richiesto e al carico.\nIl vantaggio è che i connection string dell\u0026rsquo;applicativo non cambiano mai: se un nodo viene aggiunto o rimosso dal cluster, lo SCAN gestisce tutto in modo trasparente.\nConfigurazione tipica #Un connection string che usa lo SCAN:\njdbc:oracle:thin:@//scan-name.example.com:1521/service_name I tre SCAN VIP girano su qualsiasi nodo del cluster. In un cluster a due nodi, un nodo ospita due VIP e l\u0026rsquo;altro uno (o viceversa).\nNelle migrazioni #Nelle migrazioni a OCI, lo SCAN listener viene riconfigurato con il DNS della nuova infrastruttura. È uno dei passaggi del cutover: aggiornare i connection string per puntare al nuovo SCAN name su OCI. Se il naming è gestito bene, è una modifica in un punto solo (il connection pool dell\u0026rsquo;applicativo), non in decine di file di configurazione sparsi.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/scan-listener/","section":"Glossario","summary":"\u003cp\u003eLo \u003cstrong\u003eSCAN Listener\u003c/strong\u003e (Single Client Access Name) è il componente di Oracle RAC che fornisce un unico nome DNS per l\u0026rsquo;accesso al cluster. Le applicazioni si connettono allo SCAN name senza dover conoscere i singoli nodi: il listener distribuisce automaticamente le connessioni tra i nodi attivi.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLo SCAN è un nome DNS che risolve a tre indirizzi IP virtuali (VIP), distribuiti tra i nodi del cluster. Quando un client si connette allo SCAN name, il DNS restituisce uno dei tre IP, e il listener su quell\u0026rsquo;IP redirige la connessione al nodo più appropriato in base al servizio richiesto e al carico.\u003c/p\u003e","title":"SCAN Listener"},{"content":"SCD (Slowly Changing Dimension) indica un insieme di tecniche usate nel data warehouse per gestire i cambiamenti nei dati delle tabelle dimensionali nel corso del tempo.\nI tipi principali # Tipo 1: sovrascrittura del valore precedente. Nessuna storia conservata Tipo 2: inserimento di una nuova riga con date di validità (data inizio, data fine). Conserva tutta la storia Tipo 3: aggiunta di una colonna per il valore precedente. Conserva solo l\u0026rsquo;ultimo cambiamento Perché serve #In un database transazionale, quando un cliente cambia indirizzo si aggiorna il record. In un data warehouse questo significherebbe perdere la storia: tutte le vendite precedenti risulterebbero associate al nuovo indirizzo.\nLa SCD Tipo 2 risolve questo problema mantenendo una riga per ogni versione del dato, con date di validità che permettono di ricostruire la situazione a qualsiasi punto nel tempo.\nQuando si usa #La scelta del tipo dipende dal requisito di business. Se serve solo il dato corrente, il Tipo 1 basta. Se il business ha bisogno di analisi storiche accurate — e nella maggior parte dei data warehouse reali è così — il Tipo 2 è la scelta standard.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/scd/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eSCD\u003c/strong\u003e (Slowly Changing Dimension) indica un insieme di tecniche usate nel data warehouse per gestire i cambiamenti nei dati delle tabelle dimensionali nel corso del tempo.\u003c/p\u003e\n\u003ch2 id=\"i-tipi-principali\" class=\"relative group\"\u003eI tipi principali \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#i-tipi-principali\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eTipo 1\u003c/strong\u003e: sovrascrittura del valore precedente. Nessuna storia conservata\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTipo 2\u003c/strong\u003e: inserimento di una nuova riga con date di validità (data inizio, data fine). Conserva tutta la storia\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTipo 3\u003c/strong\u003e: aggiunta di una colonna per il valore precedente. Conserva solo l\u0026rsquo;ultimo cambiamento\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"perché-serve\" class=\"relative group\"\u003ePerché serve \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#perch%c3%a9-serve\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIn un database transazionale, quando un cliente cambia indirizzo si aggiorna il record. In un data warehouse questo significherebbe perdere la storia: tutte le vendite precedenti risulterebbero associate al nuovo indirizzo.\u003c/p\u003e","title":"SCD"},{"content":"Uno Schema in un database relazionale è un namespace logico che raggruppa oggetti come tabelle, viste, funzioni e sequenze. Funziona come un contenitore organizzativo all\u0026rsquo;interno di un database.\nCome funziona #In PostgreSQL, lo schema predefinito è public. Per accedere a un oggetto in un altro schema serve il prefisso: schema1.tabella. Il privilegio USAGE su uno schema è prerequisito per accedere a qualsiasi oggetto al suo interno — senza USAGE, nemmeno un GRANT SELECT sulle tabelle funziona.\nA cosa serve #Gli schema permettono di separare logicamente i dati: uno schema per l\u0026rsquo;applicazione, uno per la reportistica, uno per le tabelle di staging. In Oracle, il concetto è diverso: ogni utente è automaticamente uno schema, e gli oggetti creati dall\u0026rsquo;utente vivono nel suo schema. In PostgreSQL, schema e utente sono entità indipendenti.\nPerché è critico #La gestione dei permessi sugli schema è la fonte più comune di errori quando si creano utenti con accesso limitato. Dimenticare il GRANT USAGE ON SCHEMA è l\u0026rsquo;errore classico che genera il messaggio \u0026ldquo;permission denied for schema\u0026rdquo; anche quando i permessi sulle tabelle sono corretti.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/schema/","section":"Glossario","summary":"\u003cp\u003eUno \u003cstrong\u003eSchema\u003c/strong\u003e in un database relazionale è un namespace logico che raggruppa oggetti come tabelle, viste, funzioni e sequenze. Funziona come un contenitore organizzativo all\u0026rsquo;interno di un database.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIn PostgreSQL, lo schema predefinito è \u003ccode\u003epublic\u003c/code\u003e. Per accedere a un oggetto in un altro schema serve il prefisso: \u003ccode\u003eschema1.tabella\u003c/code\u003e. Il privilegio \u003ccode\u003eUSAGE\u003c/code\u003e su uno schema è prerequisito per accedere a qualsiasi oggetto al suo interno — senza \u003ccode\u003eUSAGE\u003c/code\u003e, nemmeno un \u003ccode\u003eGRANT SELECT\u003c/code\u003e sulle tabelle funziona.\u003c/p\u003e","title":"Schema"},{"content":"Lo Scope (ambito) di un progetto definisce il perimetro di ciò che il progetto deve realizzare: funzionalità incluse, deliverable attesi, vincoli e confini concordati con gli stakeholder. Tutto ciò che è dentro lo scope si fa; tutto ciò che è fuori, no.\nCome funziona #Lo scope viene definito nelle fasi iniziali del progetto attraverso documenti come lo Statement of Work o il Project Charter. Ogni richiesta di modifica successiva deve passare attraverso un processo formale di change management per valutarne l\u0026rsquo;impatto su tempi, costi e risorse.\nPerché è critico #Lo scope creep — l\u0026rsquo;espansione incontrollata dei requisiti — è tra le cause principali di fallimento dei progetti IT. Ogni feature aggiunta senza rivalutare tempi e budget erode le risorse disponibili. Un PM efficace sa dire \u0026ldquo;sì, e per includerlo dobbiamo togliere quest\u0026rsquo;altro\u0026rdquo; — non semplicemente \u0026ldquo;no\u0026rdquo;.\nQuando si usa #In ogni fase del progetto: nella pianificazione per definire i confini, durante l\u0026rsquo;esecuzione per valutare le change request, nelle negoziazioni con gli stakeholder per ridirezionare le aspettative. La chiarezza sullo scope è la base di ogni decisione progettuale.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/scope/","section":"Glossario","summary":"\u003cp\u003eLo \u003cstrong\u003eScope\u003c/strong\u003e (ambito) di un progetto definisce il perimetro di ciò che il progetto deve realizzare: funzionalità incluse, deliverable attesi, vincoli e confini concordati con gli stakeholder. Tutto ciò che è dentro lo scope si fa; tutto ciò che è fuori, no.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLo scope viene definito nelle fasi iniziali del progetto attraverso documenti come lo Statement of Work o il Project Charter. Ogni richiesta di modifica successiva deve passare attraverso un processo formale di change management per valutarne l\u0026rsquo;impatto su tempi, costi e risorse.\u003c/p\u003e","title":"Scope"},{"content":"Lo Scope Creep è l\u0026rsquo;espansione progressiva e spesso non controllata dell\u0026rsquo;ambito di un progetto rispetto a quanto definito inizialmente. Nuovi requisiti, modifiche alle specifiche e funzionalità aggiuntive si accumulano senza un corrispondente adeguamento di budget e tempistiche.\nCome funziona #In un progetto software, lo scope creep inizia tipicamente con richieste apparentemente piccole: \u0026ldquo;aggiungiamo anche questo campo\u0026rdquo;, \u0026ldquo;sarebbe utile anche questa funzione\u0026rdquo;. Ogni singola modifica sembra ragionevole, ma l\u0026rsquo;effetto cumulativo è devastante. Le specifiche diventano un bersaglio mobile, il team non riesce mai a raggiungere una baseline stabile, e il progetto entra in un ciclo infinito di revisioni.\nA cosa serve #Riconoscere lo scope creep è il primo passo per prevenirlo. I meccanismi di difesa includono: change request formali con analisi di impatto, congelamento delle specifiche per fase, prioritizzazione rigorosa e la capacità di dire \u0026ldquo;no\u0026rdquo; — o almeno \u0026ldquo;non ora\u0026rdquo;.\nQuando si usa #Il termine descrive un anti-pattern di project management da evitare. Nei grandi progetti di consulenza, lo scope creep diventa spesso un\u0026rsquo;arma nelle mani del fornitore: le specifiche incomplete giustificano ritardi e costi aggiuntivi, trasformando un progetto a corpo in una consulenza a tempo indeterminato.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/scope-creep/","section":"Glossario","summary":"\u003cp\u003eLo \u003cstrong\u003eScope Creep\u003c/strong\u003e è l\u0026rsquo;espansione progressiva e spesso non controllata dell\u0026rsquo;ambito di un progetto rispetto a quanto definito inizialmente. Nuovi requisiti, modifiche alle specifiche e funzionalità aggiuntive si accumulano senza un corrispondente adeguamento di budget e tempistiche.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIn un progetto software, lo scope creep inizia tipicamente con richieste apparentemente piccole: \u0026ldquo;aggiungiamo anche questo campo\u0026rdquo;, \u0026ldquo;sarebbe utile anche questa funzione\u0026rdquo;. Ogni singola modifica sembra ragionevole, ma l\u0026rsquo;effetto cumulativo è devastante. Le specifiche diventano un bersaglio mobile, il team non riesce mai a raggiungere una baseline stabile, e il progetto entra in un ciclo infinito di revisioni.\u003c/p\u003e","title":"Scope Creep"},{"content":"Scrum è un framework agile per la gestione di progetti che organizza il lavoro in iterazioni a durata fissa chiamate sprint (tipicamente 2 settimane). Definisce tre ruoli (Product Owner, Scrum Master, Development Team) e quattro cerimonie (Sprint Planning, Daily Standup, Sprint Review, Sprint Retrospective).\nCome funziona #Ogni sprint inizia con una pianificazione, prosegue con standup quotidiani per la sincronizzazione, e termina con una review (cosa è stato fatto) e una retrospettiva (come migliorare il processo). Il timebox è il principio fondamentale: ogni cerimonia ha una durata massima non negoziabile.\nA cosa serve #Scrum fornisce struttura a team che lavorano su progetti complessi con requisiti in evoluzione. Il ciclo breve degli sprint permette feedback rapido, correzioni di rotta frequenti e visibilità continua sullo stato del progetto. Lo standup quotidiano è una delle cerimonie più riconoscibili del framework.\nCosa può andare storto #Il rischio più comune è adottare Scrum come rituale senza capirne i principi. Team che fanno lo standup ma non rispettano il timebox, sprint che non hanno un obiettivo chiaro, retrospettive che non producono azioni concrete. Scrum funziona quando è applicato con disciplina, non quando è solo un\u0026rsquo;etichetta.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/scrum/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eScrum\u003c/strong\u003e è un framework agile per la gestione di progetti che organizza il lavoro in iterazioni a durata fissa chiamate sprint (tipicamente 2 settimane). Definisce tre ruoli (Product Owner, Scrum Master, Development Team) e quattro cerimonie (Sprint Planning, Daily Standup, Sprint Review, Sprint Retrospective).\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOgni sprint inizia con una pianificazione, prosegue con standup quotidiani per la sincronizzazione, e termina con una review (cosa è stato fatto) e una retrospettiva (come migliorare il processo). Il timebox è il principio fondamentale: ogni cerimonia ha una durata massima non negoziabile.\u003c/p\u003e","title":"Scrum"},{"content":"secure-file-priv è una variabile di sistema MySQL che controlla dove le istruzioni LOAD DATA INFILE, SELECT INTO OUTFILE e la funzione LOAD_FILE() possono operare sul filesystem del server.\nCome funziona #La variabile accetta tre valori: un percorso specifico (es. /var/lib/mysql-files/), che limita le operazioni su file a quella directory; una stringa vuota (\u0026quot;\u0026quot;), che non impone alcuna restrizione; oppure NULL, che disabilita completamente le operazioni su file. Il valore è impostabile solo nel file di configurazione (my.cnf) e richiede un riavvio del servizio per essere modificato — non è cambiabile a runtime.\nA cosa serve #La direttiva previene l\u0026rsquo;accesso arbitrario al filesystem da parte di utenti MySQL con il privilegio FILE. Senza questa protezione, un attaccante che sfrutta una SQL injection potrebbe leggere file di sistema (es. /etc/passwd, chiavi SSH) o scrivere web shell nella webroot di un server web sullo stesso host.\nQuando si usa #secure-file-priv va configurata al momento del setup di ogni istanza MySQL, specificando una directory dedicata. In ambienti multi-istanza, ogni istanza dovrebbe avere la propria directory secure-file-priv. Se l\u0026rsquo;export su file è bloccato, l\u0026rsquo;alternativa consigliata è usare il client mysql da shell con le opzioni -B e -e per redirigere l\u0026rsquo;output.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/secure-file-priv/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003esecure-file-priv\u003c/strong\u003e è una variabile di sistema MySQL che controlla dove le istruzioni \u003ccode\u003eLOAD DATA INFILE\u003c/code\u003e, \u003ccode\u003eSELECT INTO OUTFILE\u003c/code\u003e e la funzione \u003ccode\u003eLOAD_FILE()\u003c/code\u003e possono operare sul filesystem del server.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa variabile accetta tre valori: un percorso specifico (es. \u003ccode\u003e/var/lib/mysql-files/\u003c/code\u003e), che limita le operazioni su file a quella directory; una stringa vuota (\u003ccode\u003e\u0026quot;\u0026quot;\u003c/code\u003e), che non impone alcuna restrizione; oppure \u003ccode\u003eNULL\u003c/code\u003e, che disabilita completamente le operazioni su file. Il valore è impostabile solo nel file di configurazione (\u003ccode\u003emy.cnf\u003c/code\u003e) e richiede un riavvio del servizio per essere modificato — non è cambiabile a runtime.\u003c/p\u003e","title":"secure-file-priv"},{"content":"Il self-parenting è una tecnica di dimensional modeling usata per bilanciare le gerarchie sbilanciate (ragged hierarchies). Il principio è semplice: un\u0026rsquo;entità che non ha un livello gerarchico superiore diventa il proprio genitore a quel livello.\nCome funziona #In una gerarchia a tre livelli Top Group → Group → Client:\nUn Client senza Group usa il proprio nome/ID come Group Un Group senza Top Group usa il proprio nome/ID come Top Group Il risultato è una tabella dimensionale senza NULL nelle colonne gerarchiche, con tutti i livelli sempre popolati.\nI flag di distinzione #Per non perdere l\u0026rsquo;informazione su quali entità sono state bilanciate artificialmente, si aggiungono flag alla dimensione:\nis_direct_client = 'Y': il client non aveva un Group nella sorgente is_standalone_group = 'Y': il Group non aveva un Top Group nella sorgente Questi flag permettono al business di filtrare i \u0026ldquo;veri\u0026rdquo; top group dai clienti promossi.\nPerché nell\u0026rsquo;ETL e non nel report #Il self-parenting si applica una volta nell\u0026rsquo;ETL, non in ogni singolo report. Un report dovrebbe fare GROUP BY e JOIN, non decidere come gestire i livelli mancanti. Se la logica di bilanciamento è nel modello, tutti i report ne beneficiano automaticamente.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/self-parenting/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eself-parenting\u003c/strong\u003e è una tecnica di dimensional modeling usata per bilanciare le gerarchie sbilanciate (ragged hierarchies). Il principio è semplice: un\u0026rsquo;entità che non ha un livello gerarchico superiore diventa il proprio genitore a quel livello.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIn una gerarchia a tre livelli Top Group → Group → Client:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUn Client senza Group usa il proprio nome/ID come Group\u003c/li\u003e\n\u003cli\u003eUn Group senza Top Group usa il proprio nome/ID come Top Group\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIl risultato è una tabella dimensionale senza NULL nelle colonne gerarchiche, con tutti i livelli sempre popolati.\u003c/p\u003e","title":"Self-parenting"},{"content":"Il Sequential Scan (Seq Scan) è l\u0026rsquo;operazione con cui PostgreSQL legge una tabella dall\u0026rsquo;inizio alla fine, blocco per blocco, senza utilizzare alcun indice. È l\u0026rsquo;equivalente PostgreSQL del Full Table Scan di Oracle.\nQuando è normale #Su tabelle piccole (poche migliaia di righe), il sequential scan è spesso la scelta più efficiente. Leggere una tabella intera in sequenza è più veloce che fare lookup su un indice quando la tabella sta in poche pagine. L\u0026rsquo;optimizer sceglie il sequential scan quando stima che sia più economico di un index scan.\nQuando è un problema #Su tabelle grandi (milioni di righe), un sequential scan per restituire poche righe è un segnale d\u0026rsquo;allarme. Significa che manca un indice appropriato o che le statistiche della tabella sono obsolete e l\u0026rsquo;optimizer fa stime sbagliate. pg_stat_statements aiuta a identificare queste situazioni mostrando le query con il peggior rapporto blocchi letti / righe restituite.\nCome diagnosticarlo #EXPLAIN mostra \u0026ldquo;Seq Scan on tabella\u0026rdquo; nel piano di esecuzione. Se il filtro successivo scarta la maggior parte delle righe (rows removed by filter \u0026raquo; rows), quasi certamente serve un indice sulla colonna del filtro.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/sequential-scan/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eSequential Scan\u003c/strong\u003e (Seq Scan) è l\u0026rsquo;operazione con cui PostgreSQL legge una tabella dall\u0026rsquo;inizio alla fine, blocco per blocco, senza utilizzare alcun indice. È l\u0026rsquo;equivalente PostgreSQL del Full Table Scan di Oracle.\u003c/p\u003e\n\u003ch2 id=\"quando-è-normale\" class=\"relative group\"\u003eQuando è normale \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#quando-%c3%a8-normale\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSu tabelle piccole (poche migliaia di righe), il sequential scan è spesso la scelta più efficiente. Leggere una tabella intera in sequenza è più veloce che fare lookup su un indice quando la tabella sta in poche pagine. L\u0026rsquo;optimizer sceglie il sequential scan quando stima che sia più economico di un index scan.\u003c/p\u003e","title":"Sequential Scan"},{"content":"La SGA (System Global Area) è l\u0026rsquo;area di memoria condivisa principale di Oracle Database. Contiene le strutture dati fondamentali: buffer cache (pagine dati lette da disco), shared pool (piani di esecuzione e dizionario dati), redo log buffer e large pool.\nCome funziona #La dimensione della SGA è controllata dal parametro SGA_TARGET o SGA_MAX_SIZE. Oracle alloca la SGA all\u0026rsquo;avvio dell\u0026rsquo;istanza in memoria condivisa del sistema operativo. I parametri kernel Linux shmmax e shmall devono essere dimensionati per permettere l\u0026rsquo;allocazione completa della SGA.\nA cosa serve #Tutta l\u0026rsquo;attività di lettura e scrittura del database passa attraverso la SGA. Un buffer cache efficiente evita letture fisiche da disco. Uno shared pool ben dimensionato evita re-parsing delle query. La SGA è il cuore delle performance Oracle — e deve risiedere in Huge Pages per massimizzare l\u0026rsquo;efficienza.\nPerché è critico #Una SGA non allocata in Huge Pages significa milioni di entry nella Page Table e overflow costante del TLB. Il risultato sono latch free wait, library cache contention e CPU elevata. Configurare le Huge Pages e il parametro memlock unlimited per l\u0026rsquo;utente oracle è il prerequisito per qualsiasi tuning serio.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/sga/","section":"Glossario","summary":"\u003cp\u003eLa \u003cstrong\u003eSGA\u003c/strong\u003e (System Global Area) è l\u0026rsquo;area di memoria condivisa principale di Oracle Database. Contiene le strutture dati fondamentali: buffer cache (pagine dati lette da disco), shared pool (piani di esecuzione e dizionario dati), redo log buffer e large pool.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa dimensione della SGA è controllata dal parametro \u003ccode\u003eSGA_TARGET\u003c/code\u003e o \u003ccode\u003eSGA_MAX_SIZE\u003c/code\u003e. Oracle alloca la SGA all\u0026rsquo;avvio dell\u0026rsquo;istanza in memoria condivisa del sistema operativo. I parametri kernel Linux \u003ccode\u003eshmmax\u003c/code\u003e e \u003ccode\u003eshmall\u003c/code\u003e devono essere dimensionati per permettere l\u0026rsquo;allocazione completa della SGA.\u003c/p\u003e","title":"SGA"},{"content":"shared_buffers è il parametro che controlla la dimensione dell\u0026rsquo;area di memoria condivisa usata da PostgreSQL come cache per i blocchi dati letti dal disco. Ogni volta che PostgreSQL legge una pagina dati (8 KB), la conserva in shared_buffers per le letture successive.\nCome funziona #PostgreSQL alloca la memoria per shared_buffers all\u0026rsquo;avvio del servizio. Tutti i processi backend condividono questa area di memoria. Quando un processo ha bisogno di un blocco dati, cerca prima in shared_buffers. Se lo trova (cache hit), la lettura è immediata. Se non lo trova (cache miss), deve leggere dal disco — un\u0026rsquo;operazione ordini di grandezza più lenta.\nQuanto allocare #Il valore di default è 128 MB — inadeguato per qualsiasi database di produzione. La regola empirica è impostare shared_buffers al 25% della RAM disponibile. Su un server con 64 GB di RAM, 16 GB è un buon punto di partenza. Valori oltre il 40% della RAM raramente portano benefici perché PostgreSQL si appoggia anche alla cache del sistema operativo.\nCome monitorarlo #La vista pg_stat_bgwriter mostra il rapporto tra buffers_alloc (nuovi blocchi allocati) e il totale dei blocchi serviti. Un cache hit ratio sotto il 95% suggerisce che shared_buffers potrebbe essere sottodimensionato.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/shared-buffers/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eshared_buffers\u003c/strong\u003e è il parametro che controlla la dimensione dell\u0026rsquo;area di memoria condivisa usata da PostgreSQL come cache per i blocchi dati letti dal disco. Ogni volta che PostgreSQL legge una pagina dati (8 KB), la conserva in shared_buffers per le letture successive.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003ePostgreSQL alloca la memoria per shared_buffers all\u0026rsquo;avvio del servizio. Tutti i processi backend condividono questa area di memoria. Quando un processo ha bisogno di un blocco dati, cerca prima in shared_buffers. Se lo trova (cache hit), la lettura è immediata. Se non lo trova (cache miss), deve leggere dal disco — un\u0026rsquo;operazione ordini di grandezza più lenta.\u003c/p\u003e","title":"shared_buffers"},{"content":"Single-primary è la modalità operativa più comune di MySQL Group Replication, in cui un solo nodo del cluster — il primary — accetta operazioni di scrittura. Gli altri nodi (secondary) sono in sola lettura (read_only=ON, super_read_only=ON) e ricevono le modifiche tramite la replica sincrona del gruppo.\nCome funziona #Il parametro group_replication_single_primary_mode=ON attiva questa modalità. Il primary è l\u0026rsquo;unico nodo con read_only=OFF. Se il primary viene fermato o diventa irraggiungibile, il cluster esegue un\u0026rsquo;elezione automatica e uno dei secondary diventa il nuovo primary in pochi secondi.\nPerché si usa #La modalità single-primary evita i conflitti di scrittura concorrente tipici del multi-primary. In produzione la maggior parte dei cluster MySQL usa questa modalità perché è più prevedibile: le applicazioni scrivono su un solo endpoint, la replica è lineare e il debugging è più semplice.\nCosa può andare storto #Quando si ferma il primary per manutenzione, il cluster fa un failover automatico. Durante quei secondi le connessioni attive possono essere interrotte e le transazioni in corso possono fallire. È un disservizio breve ma va comunicato. La regola pratica: in un intervento di manutenzione su un cluster single-primary, i secondary si toccano prima, il primary per ultimo.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/single-primary/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eSingle-primary\u003c/strong\u003e è la modalità operativa più comune di MySQL Group Replication, in cui un solo nodo del cluster — il primary — accetta operazioni di scrittura. Gli altri nodi (secondary) sono in sola lettura (\u003ccode\u003eread_only=ON\u003c/code\u003e, \u003ccode\u003esuper_read_only=ON\u003c/code\u003e) e ricevono le modifiche tramite la replica sincrona del gruppo.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl parametro \u003ccode\u003egroup_replication_single_primary_mode=ON\u003c/code\u003e attiva questa modalità. Il primary è l\u0026rsquo;unico nodo con \u003ccode\u003eread_only=OFF\u003c/code\u003e. Se il primary viene fermato o diventa irraggiungibile, il cluster esegue un\u0026rsquo;elezione automatica e uno dei secondary diventa il nuovo primary in pochi secondi.\u003c/p\u003e","title":"Single-primary"},{"content":"Lo Smart Working (lavoro agile) è un modello organizzativo che permette al dipendente di lavorare da qualsiasi luogo, combinando giornate in ufficio e giornate da remoto, con orari flessibili e valutazione basata sui risultati invece che sulla presenza.\nCome funziona #Il modello tipico è 80/20: 80% remoto, 20% in presenza. I giorni in ufficio servono per workshop, review di progetto e team building — non per scaldare la sedia. L\u0026rsquo;azienda fornisce attrezzatura per la postazione domestica (monitor, sedia ergonomica, cuffie) e un contributo per la connettività.\nA cosa serve #Nella consulenza IT, lo smart working elimina il costo del pendolarismo (fino a 90 ore/mese per un consulente romano), riduce i costi immobiliari (da 50 postazioni fisse a 15 hot desk) e restituisce ore di produttività reale. Un consulente che inizia a lavorare alle 7:45 fresco e concentrato produce più di uno che arriva alle 9:30 stressato dal traffico.\nPerché è critico #Lo smart working non è un benefit — è un modello organizzativo che richiede KPI chiari, fiducia reciproca e strumenti di comunicazione adeguati. Le aziende che lo adottano come \u0026ldquo;concessione\u0026rdquo; invece che come \u0026ldquo;strategia\u0026rdquo; ne perdono i benefici. Quelle che lo rifiutano per presenteismo pagano un costo invisibile in produttività persa e talenti in fuga.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/smart-working/","section":"Glossario","summary":"\u003cp\u003eLo \u003cstrong\u003eSmart Working\u003c/strong\u003e (lavoro agile) è un modello organizzativo che permette al dipendente di lavorare da qualsiasi luogo, combinando giornate in ufficio e giornate da remoto, con orari flessibili e valutazione basata sui risultati invece che sulla presenza.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl modello tipico è 80/20: 80% remoto, 20% in presenza. I giorni in ufficio servono per workshop, review di progetto e team building — non per scaldare la sedia. L\u0026rsquo;azienda fornisce attrezzatura per la postazione domestica (monitor, sedia ergonomica, cuffie) e un contributo per la connettività.\u003c/p\u003e","title":"Smart Working"},{"content":"Snapshot in Oracle è un\u0026rsquo;istantanea delle statistiche di performance del database catturata in un preciso momento e conservata nel repository AWR. Di default Oracle genera uno snapshot ogni 60 minuti e li conserva per 8 giorni.\nCome funziona #Ogni snapshot registra centinaia di metriche: wait event, statistiche SQL, metriche di memoria (SGA, PGA), I/O per datafile, statistiche di sistema. Il confronto tra due snapshot genera il report AWR, che mostra cosa è cambiato tra i due istanti.\nSnapshot manuali #In situazioni di emergenza è possibile generare uno snapshot manuale per catturare lo stato corrente:\nEXEC DBMS_WORKLOAD_REPOSITORY.create_snapshot; Questo è utile quando si vuole un punto di riferimento immediato — ad esempio, prima e dopo un deploy — senza aspettare il ciclo automatico.\nGestione #Gli snapshot sono consultabili tramite la vista DBA_HIST_SNAPSHOT. La retention (quanti giorni conservarli) e l\u0026rsquo;intervallo (ogni quanti minuti generarli) si configurano con:\nEXEC DBMS_WORKLOAD_REPOSITORY.modify_snapshot_settings( retention =\u0026gt; 43200, -- 30 giorni in minuti interval =\u0026gt; 30 -- ogni 30 minuti ); Perché sono importanti #Senza snapshot, non c\u0026rsquo;è AWR. Senza AWR, la diagnosi di un problema di performance diventa un esercizio di intuizione anziché un\u0026rsquo;analisi basata sui dati. Gli snapshot sono le fondamenta dell\u0026rsquo;osservabilità in Oracle.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/snapshot-oracle/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eSnapshot\u003c/strong\u003e in Oracle è un\u0026rsquo;istantanea delle statistiche di performance del database catturata in un preciso momento e conservata nel repository AWR. Di default Oracle genera uno snapshot ogni 60 minuti e li conserva per 8 giorni.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOgni snapshot registra centinaia di metriche: wait event, statistiche SQL, metriche di memoria (SGA, PGA), I/O per datafile, statistiche di sistema. Il confronto tra due snapshot genera il report AWR, che mostra cosa è cambiato tra i due istanti.\u003c/p\u003e","title":"Snapshot (Oracle)"},{"content":"Lo split-brain è una condizione critica che si verifica quando un cluster database si divide in due o più partizioni che non possono comunicare tra loro, e ciascuna partizione continua ad accettare scritture indipendentemente. Il risultato sono dati divergenti impossibili da riconciliare automaticamente.\nCome funziona #In un cluster a 3 nodi, se la rete tra il Nodo 1 e i Nodi 2-3 si interrompe, senza protezione dal quorum entrambe le parti potrebbero continuare ad accettare scritture. Quando la rete si ripristina, il cluster si troverebbe con due versioni diverse degli stessi dati. Il meccanismo di quorum previene questo scenario: solo la partizione con la maggioranza dei nodi (quorum) può continuare ad operare.\nA cosa serve #Comprendere lo split-brain è fondamentale per progettare cluster database affidabili. È la ragione principale per cui Galera Cluster richiede un numero dispari di nodi (3, 5, 7) e implementa il meccanismo di quorum. Con un numero pari di nodi, una partizione di rete può dividere il cluster in due metà uguali, nessuna delle quali ha quorum.\nQuando si usa #Il termine split-brain descrive un rischio da evitare, non una funzionalità da attivare. In Galera, la protezione è automatica: i nodi che perdono il quorum passano allo stato Non-Primary e rifiutano le scritture. Il parametro pc.ignore_quorum disabilita questa protezione, ma usarlo in produzione è fortemente sconsigliato.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/split-brain/","section":"Glossario","summary":"\u003cp\u003eLo \u003cstrong\u003esplit-brain\u003c/strong\u003e è una condizione critica che si verifica quando un cluster database si divide in due o più partizioni che non possono comunicare tra loro, e ciascuna partizione continua ad accettare scritture indipendentemente. Il risultato sono dati divergenti impossibili da riconciliare automaticamente.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIn un cluster a 3 nodi, se la rete tra il Nodo 1 e i Nodi 2-3 si interrompe, senza protezione dal quorum entrambe le parti potrebbero continuare ad accettare scritture. Quando la rete si ripristina, il cluster si troverebbe con due versioni diverse degli stessi dati. Il meccanismo di quorum previene questo scenario: solo la partizione con la maggioranza dei nodi (quorum) può continuare ad operare.\u003c/p\u003e","title":"Split-brain"},{"content":"La SQL Injection è una delle vulnerabilità più diffuse e pericolose nelle applicazioni web. Si verifica quando input forniti dall\u0026rsquo;utente vengono inseriti direttamente nelle query SQL senza validazione o parametrizzazione, permettendo a un attaccante di modificare la logica della query.\nCome funziona #L\u0026rsquo;attaccante inserisce frammenti di codice SQL nei campi di input dell\u0026rsquo;applicazione (form di login, campi di ricerca, parametri URL). Se l\u0026rsquo;applicazione concatena questi input direttamente nelle query SQL, il codice malevolo viene eseguito dal database con i privilegi dell\u0026rsquo;utente applicativo. In combinazione con il privilegio FILE di MySQL e un secure-file-priv non configurato, l\u0026rsquo;attaccante può leggere file di sistema o scrivere file arbitrari sul server.\nA cosa serve #Comprendere la SQL injection è fondamentale per chi gestisce database in produzione, perché molte configurazioni di sicurezza (come secure-file-priv, la gestione dei privilegi e la separazione degli utenti) esistono specificamente per mitigare l\u0026rsquo;impatto di questo tipo di attacco.\nQuando si usa #Il termine descrive un attacco da prevenire, non una tecnica da utilizzare. Le contromisure principali sono: query parametrizzate (prepared statements), validazione degli input, principio del minimo privilegio per gli utenti database, e configurazione corretta di direttive come secure-file-priv.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/sql-injection/","section":"Glossario","summary":"\u003cp\u003eLa \u003cstrong\u003eSQL Injection\u003c/strong\u003e è una delle vulnerabilità più diffuse e pericolose nelle applicazioni web. Si verifica quando input forniti dall\u0026rsquo;utente vengono inseriti direttamente nelle query SQL senza validazione o parametrizzazione, permettendo a un attaccante di modificare la logica della query.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eL\u0026rsquo;attaccante inserisce frammenti di codice SQL nei campi di input dell\u0026rsquo;applicazione (form di login, campi di ricerca, parametri URL). Se l\u0026rsquo;applicazione concatena questi input direttamente nelle query SQL, il codice malevolo viene eseguito dal database con i privilegi dell\u0026rsquo;utente applicativo. In combinazione con il privilegio \u003ccode\u003eFILE\u003c/code\u003e di MySQL e un \u003ccode\u003esecure-file-priv\u003c/code\u003e non configurato, l\u0026rsquo;attaccante può leggere file di sistema o scrivere file arbitrari sul server.\u003c/p\u003e","title":"SQL Injection"},{"content":"SST (State Snapshot Transfer) è il meccanismo con cui un nodo Galera che si unisce al cluster (o che è rimasto offline troppo a lungo) riceve una copia completa dell\u0026rsquo;intero dataset da un nodo donatore.\nCome funziona #Quando un nodo si unisce al cluster e il gap di transazioni mancanti supera la dimensione del gcache, il cluster avvia un SST. Il nodo donatore crea un\u0026rsquo;istantanea completa del database e la trasferisce al nodo ricevente. I metodi disponibili sono: mariabackup (non blocca il donatore), rsync (veloce ma blocca il donatore in lettura), e mysqldump (lento e bloccante).\nA cosa serve #SST è essenziale per due scenari: l\u0026rsquo;aggiunta di un nuovo nodo al cluster (primo join) e il recupero di un nodo che è rimasto offline così a lungo che le transazioni mancanti non sono più disponibili nel gcache del donatore.\nQuando si usa #SST viene attivato automaticamente da Galera quando necessario. La scelta del metodo SST (wsrep_sst_method) va fatta in fase di configurazione. In produzione, mariabackup è la scelta raccomandata perché non blocca il nodo donatore, evitando di degradare il cluster durante il trasferimento.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/sst/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eSST\u003c/strong\u003e (State Snapshot Transfer) è il meccanismo con cui un nodo Galera che si unisce al cluster (o che è rimasto offline troppo a lungo) riceve una copia completa dell\u0026rsquo;intero dataset da un nodo donatore.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando un nodo si unisce al cluster e il gap di transazioni mancanti supera la dimensione del gcache, il cluster avvia un SST. Il nodo donatore crea un\u0026rsquo;istantanea completa del database e la trasferisce al nodo ricevente. I metodi disponibili sono: \u003ccode\u003emariabackup\u003c/code\u003e (non blocca il donatore), \u003ccode\u003ersync\u003c/code\u003e (veloce ma blocca il donatore in lettura), e \u003ccode\u003emysqldump\u003c/code\u003e (lento e bloccante).\u003c/p\u003e","title":"SST"},{"content":"Uno Stakeholder è qualsiasi persona, gruppo o organizzazione che ha un interesse diretto o indiretto nel risultato di un progetto. Include committenti, sponsor, utenti finali, team di sviluppo, management e fornitori esterni.\nCome funziona #Nel project management, gli stakeholder vengono identificati, classificati per livello di influenza e interesse, e gestiti con strategie di comunicazione differenziate. Uno stakeholder ad alta influenza e alto interesse (come il CTO) richiede coinvolgimento attivo; uno a bassa influenza richiede solo aggiornamenti periodici.\nPerché è critico #La maggior parte dei fallimenti progettuali non è tecnica — è relazionale. Stakeholder non allineati, aspettative non gestite e comunicazione carente sono le cause più frequenti di ritardi, scope creep e conflitti. Il PM efficace dedica più tempo alla gestione degli stakeholder che alla gestione delle timeline.\nQuando si usa #In ogni fase del progetto: nella definizione dei requisiti (chi decide cosa va fatto), nella pianificazione (chi approva le risorse), nell\u0026rsquo;esecuzione (chi valida i deliverable) e nella chiusura (chi accetta il risultato). Ignorare uno stakeholder chiave è il modo più rapido per far deragliare un progetto.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/stakeholder/","section":"Glossario","summary":"\u003cp\u003eUno \u003cstrong\u003eStakeholder\u003c/strong\u003e è qualsiasi persona, gruppo o organizzazione che ha un interesse diretto o indiretto nel risultato di un progetto. Include committenti, sponsor, utenti finali, team di sviluppo, management e fornitori esterni.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eNel project management, gli stakeholder vengono identificati, classificati per livello di influenza e interesse, e gestiti con strategie di comunicazione differenziate. Uno stakeholder ad alta influenza e alto interesse (come il CTO) richiede coinvolgimento attivo; uno a bassa influenza richiede solo aggiornamenti periodici.\u003c/p\u003e","title":"Stakeholder"},{"content":"Lo star schema (schema a stella) è il modello di dati più usato nel data warehouse. Prende il nome dalla sua forma: una tabella centrale dei fatti (fact table) collegata a più tabelle dimensionali che le stanno intorno, come i raggi di una stella.\nStruttura # Fact table al centro: contiene le misure numeriche e le foreign key verso le dimensioni Dimension tables intorno: contengono gli attributi descrittivi (chi, cosa, dove, quando) con struttura denormalizzata Le dimensioni nello star schema sono tipicamente denormalizzate — tutti gli attributi in una sola tabella piatta, senza gerarchie normalizzate. Questo semplifica le query e migliora le performance delle aggregazioni.\nPerché funziona #Lo star schema è ottimizzato per le query analitiche:\nI join sono semplici: la fact si collega direttamente a ogni dimensione con un singolo join Le aggregazioni sono veloci: gli optimizer dei database riconoscono il pattern e lo ottimizzano È intuitivo per gli utenti business: la struttura rispecchia il modo in cui pensano ai dati (vendite per prodotto, per regione, per periodo) Star schema vs Snowflake #Lo snowflake schema normalizza le dimensioni, spezzandole in sotto-tabelle. Risparmia spazio ma complica le query con join aggiuntivi. Nella pratica, lo star schema è preferito nella maggior parte dei casi perché la semplicità delle query compensa ampiamente il costo dello spazio extra nelle dimensioni.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/star-schema/","section":"Glossario","summary":"\u003cp\u003eLo \u003cstrong\u003estar schema\u003c/strong\u003e (schema a stella) è il modello di dati più usato nel data warehouse. Prende il nome dalla sua forma: una tabella centrale dei fatti (fact table) collegata a più tabelle dimensionali che le stanno intorno, come i raggi di una stella.\u003c/p\u003e\n\u003ch2 id=\"struttura\" class=\"relative group\"\u003eStruttura \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#struttura\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eFact table\u003c/strong\u003e al centro: contiene le misure numeriche e le foreign key verso le dimensioni\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDimension tables\u003c/strong\u003e intorno: contengono gli attributi descrittivi (chi, cosa, dove, quando) con struttura denormalizzata\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eLe dimensioni nello star schema sono tipicamente denormalizzate — tutti gli attributi in una sola tabella piatta, senza gerarchie normalizzate. Questo semplifica le query e migliora le performance delle aggregazioni.\u003c/p\u003e","title":"Star schema"},{"content":"La Swappiness (vm.swappiness) è un parametro del kernel Linux che controlla quanto aggressivamente il sistema sposta pagine di memoria dalla RAM allo swap su disco. Il valore va da 0 (swap solo in caso estremo) a 100 (swap aggressivo). Il default è 60.\nCome funziona #Con il valore di default 60, Linux inizia a swappare quando la pressione sulla memoria è ancora relativamente bassa. Per un server database dedicato, questo è inaccettabile: l\u0026rsquo;SGA deve restare in RAM, sempre. Il valore raccomandato per Oracle è 1 — non 0, che disabiliterebbe completamente lo swap e potrebbe causare OOM killer.\nA cosa serve #Il valore 1 dice al kernel: \u0026ldquo;Swappa solo se non c\u0026rsquo;è davvero più alternativa.\u0026rdquo; Questo garantisce che la SGA e le strutture critiche di Oracle restino in memoria fisica, evitando letture da swap (ordini di grandezza più lente della RAM) durante l\u0026rsquo;esecuzione delle query.\nPerché è critico #Con swappiness a 60, un server con 128 GB di RAM e 64 GB di SGA può iniziare a swappare parti della SGA anche con 20-30 GB di RAM libera. Il risultato sono performance degradate in modo imprevedibile, con picchi di latenza che sembrano problemi applicativi ma sono in realtà il sistema operativo che sposta memoria su disco.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/swappiness/","section":"Glossario","summary":"\u003cp\u003eLa \u003cstrong\u003eSwappiness\u003c/strong\u003e (\u003ccode\u003evm.swappiness\u003c/code\u003e) è un parametro del kernel Linux che controlla quanto aggressivamente il sistema sposta pagine di memoria dalla RAM allo swap su disco. Il valore va da 0 (swap solo in caso estremo) a 100 (swap aggressivo). Il default è 60.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCon il valore di default 60, Linux inizia a swappare quando la pressione sulla memoria è ancora relativamente bassa. Per un server database dedicato, questo è inaccettabile: l\u0026rsquo;SGA deve restare in RAM, sempre. Il valore raccomandato per Oracle è 1 — non 0, che disabiliterebbe completamente lo swap e potrebbe causare OOM killer.\u003c/p\u003e","title":"Swappiness"},{"content":"Lo switchover è un\u0026rsquo;operazione pianificata di Oracle Data Guard che inverte i ruoli tra il database primary e lo standby. Il primary diventa standby, lo standby diventa primary. Nessun dato viene perso, nessuna transazione va in errore — è un passaggio pulito e controllato.\nSwitchover vs Failover #La distinzione è fondamentale:\nSwitchover Failover Quando Pianificato (manutenzione, migrazione) Emergenza (guasto del primary) Perdita dati Zero Possibile (dipende dalla modalità) Reversibilità Sì, con un altro switchover No, lo standby diventa primary in modo permanente Tempo Minuti (tipicamente 1-3) Secondi-minuti Come si esegue #Con Data Guard Broker, lo switchover è un singolo comando:\nDGMGRL\u0026gt; SWITCHOVER TO standby_db; Il broker gestisce automaticamente la sequenza: arresto del redo transport, applicazione degli ultimi redo sullo standby, inversione dei ruoli, riavvio del redo transport nella direzione opposta.\nUso nelle migrazioni #Lo switchover è la strategia preferita per le migrazioni Oracle cross-site. Si configura il Data Guard tra l\u0026rsquo;ambiente sorgente e quello di destinazione, si lascia sincronizzare, e al momento del cutover si esegue lo switchover. Se qualcosa va storto nella nuova infrastruttura, un secondo switchover riporta tutto al punto di partenza — una rete di sicurezza che Data Pump non può offrire.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/switchover/","section":"Glossario","summary":"\u003cp\u003eLo \u003cstrong\u003eswitchover\u003c/strong\u003e è un\u0026rsquo;operazione pianificata di Oracle Data Guard che inverte i ruoli tra il database primary e lo standby. Il primary diventa standby, lo standby diventa primary. Nessun dato viene perso, nessuna transazione va in errore — è un passaggio pulito e controllato.\u003c/p\u003e\n\u003ch2 id=\"switchover-vs-failover\" class=\"relative group\"\u003eSwitchover vs Failover \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#switchover-vs-failover\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eLa distinzione è fondamentale:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e\u003c/th\u003e\n          \u003cth\u003eSwitchover\u003c/th\u003e\n          \u003cth\u003eFailover\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eQuando\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003ePianificato (manutenzione, migrazione)\u003c/td\u003e\n          \u003ctd\u003eEmergenza (guasto del primary)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePerdita dati\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eZero\u003c/td\u003e\n          \u003ctd\u003ePossibile (dipende dalla modalità)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eReversibilità\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eSì, con un altro switchover\u003c/td\u003e\n          \u003ctd\u003eNo, lo standby diventa primary in modo permanente\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eTempo\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eMinuti (tipicamente 1-3)\u003c/td\u003e\n          \u003ctd\u003eSecondi-minuti\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"come-si-esegue\" class=\"relative group\"\u003eCome si esegue \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-si-esegue\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eCon Data Guard Broker, lo switchover è un singolo comando:\u003c/p\u003e","title":"Switchover"},{"content":"Un System Privilege in Oracle è un\u0026rsquo;autorizzazione che permette di eseguire operazioni globali sul database, indipendentemente da uno specifico oggetto. Esempi tipici includono CREATE TABLE, CREATE SESSION, ALTER SYSTEM, CREATE USER e DROP ANY TABLE.\nCome funziona #I system privileges si assegnano con GRANT e si revocano con REVOKE. Possono essere assegnati direttamente a un utente o a un ruolo. Il ruolo predefinito DBA include oltre 200 system privileges, motivo per cui assegnarlo a utenti applicativi è una pratica pericolosa.\nA cosa serve #I system privileges definiscono cosa un utente può fare a livello di database: creare oggetti, gestire utenti, modificare parametri di sistema. Sono il livello più alto di autorizzazione in Oracle e devono essere gestiti con estrema cautela, seguendo il principio del least privilege.\nCosa può andare storto #Un system privilege come DROP ANY TABLE permette di eliminare qualsiasi tabella di qualsiasi schema. Se assegnato per errore a un utente applicativo, un singolo comando può distruggere dati di produzione. La distinzione tra system privileges e object privileges è fondamentale per costruire un modello di sicurezza robusto.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/system-privilege/","section":"Glossario","summary":"\u003cp\u003eUn \u003cstrong\u003eSystem Privilege\u003c/strong\u003e in Oracle è un\u0026rsquo;autorizzazione che permette di eseguire operazioni globali sul database, indipendentemente da uno specifico oggetto. Esempi tipici includono \u003ccode\u003eCREATE TABLE\u003c/code\u003e, \u003ccode\u003eCREATE SESSION\u003c/code\u003e, \u003ccode\u003eALTER SYSTEM\u003c/code\u003e, \u003ccode\u003eCREATE USER\u003c/code\u003e e \u003ccode\u003eDROP ANY TABLE\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eI system privileges si assegnano con \u003ccode\u003eGRANT\u003c/code\u003e e si revocano con \u003ccode\u003eREVOKE\u003c/code\u003e. Possono essere assegnati direttamente a un utente o a un ruolo. Il ruolo predefinito \u003ccode\u003eDBA\u003c/code\u003e include oltre 200 system privileges, motivo per cui assegnarlo a utenti applicativi è una pratica pericolosa.\u003c/p\u003e","title":"System Privilege"},{"content":"systemd è il sistema di init e il gestore dei servizi predefinito nelle distribuzioni Linux moderne (CentOS/RHEL 7+, Ubuntu 16.04+, Debian 8+). In ambito database, è il meccanismo che avvia, ferma e monitora le istanze MySQL o MariaDB.\nCome funziona #Ogni servizio è definito da un file unit (es. mysqld.service) che specifica il comando di avvio, il file di configurazione, le dipendenze e il comportamento in caso di crash. In un setup multi-istanza, si creano unit file separati per ogni istanza (es. mysqld-app2.service, mysqld-reporting.service), ciascuno con il proprio --defaults-file che punta a un my.cnf diverso.\nA cosa serve #systemd permette di gestire le istanze MySQL come servizi indipendenti: avviarle, fermarle, riavviarle e monitorarle separatamente. Il comando systemctl cat \u0026lt;servizio\u0026gt; è fondamentale per risalire dal nome del servizio al file di configurazione dell\u0026rsquo;istanza, e da lì a porta, socket e datadir.\nQuando si usa #systemd è attivo automaticamente su qualsiasi server Linux moderno. In ambito DBA, si interagisce con esso tramite systemctl start/stop/status/restart \u0026lt;servizio\u0026gt;. In ambienti multi-istanza, systemctl list-units --type=service | grep mysql è il primo comando per identificare quante istanze sono attive su un server.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/systemd/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003esystemd\u003c/strong\u003e è il sistema di init e il gestore dei servizi predefinito nelle distribuzioni Linux moderne (CentOS/RHEL 7+, Ubuntu 16.04+, Debian 8+). In ambito database, è il meccanismo che avvia, ferma e monitora le istanze MySQL o MariaDB.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOgni servizio è definito da un file unit (es. \u003ccode\u003emysqld.service\u003c/code\u003e) che specifica il comando di avvio, il file di configurazione, le dipendenze e il comportamento in caso di crash. In un setup multi-istanza, si creano unit file separati per ogni istanza (es. \u003ccode\u003emysqld-app2.service\u003c/code\u003e, \u003ccode\u003emysqld-reporting.service\u003c/code\u003e), ciascuno con il proprio \u003ccode\u003e--defaults-file\u003c/code\u003e che punta a un \u003ccode\u003emy.cnf\u003c/code\u003e diverso.\u003c/p\u003e","title":"systemd"},{"content":"Un Tablespace è l\u0026rsquo;unità logica di organizzazione dello storage in Oracle Database. Ogni tablespace è composto da uno o più datafile fisici sul disco, e ogni oggetto del database (tabella, indice, partizione) risiede in un tablespace.\nCome funziona #Oracle separa la gestione logica (tablespace) da quella fisica (datafile). Un DBA può creare tablespace dedicati per scopi diversi: uno per i dati attivi, uno per gli indici, uno per l\u0026rsquo;archivio. Questo permette di distribuire il carico I/O su dischi diversi e di applicare politiche di gestione differenziate (es. read-only per i dati storici).\nA cosa serve #Nel contesto del partitioning, i tablespace permettono strategie di lifecycle management avanzate: spostare partizioni vecchie su tablespace di archivio economici, metterle in read-only per ridurre il carico di backup, e recuperare spazio attivo senza cancellare dati. Un ALTER TABLE MOVE PARTITION ... TABLESPACE ts_archive è un\u0026rsquo;operazione DDL che richiede meno di un secondo.\nQuando si usa #Ogni installazione Oracle usa tablespace. La progettazione dei tablespace diventa critica quando si gestiscono tabelle di centinaia di GB con partitioning, perché una buona distribuzione su tablespace separati abilita backup incrementali efficienti e gestione del ciclo di vita dei dati.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/tablespace/","section":"Glossario","summary":"\u003cp\u003eUn \u003cstrong\u003eTablespace\u003c/strong\u003e è l\u0026rsquo;unità logica di organizzazione dello storage in Oracle Database. Ogni tablespace è composto da uno o più datafile fisici sul disco, e ogni oggetto del database (tabella, indice, partizione) risiede in un tablespace.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOracle separa la gestione logica (tablespace) da quella fisica (datafile). Un DBA può creare tablespace dedicati per scopi diversi: uno per i dati attivi, uno per gli indici, uno per l\u0026rsquo;archivio. Questo permette di distribuire il carico I/O su dischi diversi e di applicare politiche di gestione differenziate (es. read-only per i dati storici).\u003c/p\u003e","title":"Tablespace"},{"content":"Le THP (Transparent Huge Pages) sono una funzione del kernel Linux che promuove automaticamente le pagine di memoria da 4 KB a 2 MB in background, senza configurazione esplicita. A differenza delle Huge Pages statiche, sono gestite dal processo kernel khugepaged.\nCome funziona #Quando attive (default always), il kernel tenta di compattare le pagine normali in pagine grandi in background. Il processo khugepaged lavora continuamente per trovare e unire gruppi di pagine contigue, causando micro-freeze imprevedibili durante le operazioni di compattazione.\nPerché è critico #Per Oracle sono un disastro. Oracle lo dice esplicitamente nella documentazione: disabilitare THP. I \u0026ldquo;blocchi di qualche secondo\u0026rdquo; che gli utenti lamentano sono spesso causati da khugepaged. Si disabilitano con echo never \u0026gt; /sys/kernel/mm/transparent_hugepage/enabled e via GRUB per la persistenza al reboot.\nCosa può andare storto #La confusione tra Huge Pages (buone per Oracle, configurate staticamente) e THP (dannose per Oracle, attive di default) è uno degli errori più comuni. Un DBA che vede \u0026ldquo;Huge Pages\u0026rdquo; nella documentazione e non disabilita THP sta peggiorando le cose invece di migliorarle.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/thp/","section":"Glossario","summary":"\u003cp\u003eLe \u003cstrong\u003eTHP\u003c/strong\u003e (Transparent Huge Pages) sono una funzione del kernel Linux che promuove automaticamente le pagine di memoria da 4 KB a 2 MB in background, senza configurazione esplicita. A differenza delle Huge Pages statiche, sono gestite dal processo kernel \u003ccode\u003ekhugepaged\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando attive (default \u003ccode\u003ealways\u003c/code\u003e), il kernel tenta di compattare le pagine normali in pagine grandi in background. Il processo \u003ccode\u003ekhugepaged\u003c/code\u003e lavora continuamente per trovare e unire gruppi di pagine contigue, causando micro-freeze imprevedibili durante le operazioni di compattazione.\u003c/p\u003e","title":"THP"},{"content":"Il Timeboxing è una tecnica di gestione del tempo che consiste nell\u0026rsquo;assegnare un intervallo temporale fisso e non negoziabile a un\u0026rsquo;attività. Quando il tempo scade, l\u0026rsquo;attività si chiude — indipendentemente dal fatto che sia stata completata o meno.\nCome funziona #Si definisce la durata massima (15 minuti per uno standup, 1 ora per una riunione di design, 2 settimane per uno sprint) e si rispetta il vincolo. Il timebox forza le persone a concentrarsi sull\u0026rsquo;essenziale, evitando discussioni infinite e perfezionismo paralizzante.\nA cosa serve #Nel project management, il timeboxing è alla base dello standup meeting (15 minuti massimo), dello sprint Scrum (durata fissa), e di qualsiasi riunione ben gestita. Senza vincolo temporale, le riunioni si espandono fino a occupare tutto il tempo disponibile — la legge di Parkinson applicata alle meeting room.\nPerché è critico #Uno standup da 15 minuti costa al team 440 ore all\u0026rsquo;anno. Uno da 45 minuti ne costa 1.320. La differenza — 880 ore — equivale a quasi 5 mesi-uomo. Il timeboxing non è rigidità: è rispetto per il tempo delle persone.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/timeboxing/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eTimeboxing\u003c/strong\u003e è una tecnica di gestione del tempo che consiste nell\u0026rsquo;assegnare un intervallo temporale fisso e non negoziabile a un\u0026rsquo;attività. Quando il tempo scade, l\u0026rsquo;attività si chiude — indipendentemente dal fatto che sia stata completata o meno.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSi definisce la durata massima (15 minuti per uno standup, 1 ora per una riunione di design, 2 settimane per uno sprint) e si rispetta il vincolo. Il timebox forza le persone a concentrarsi sull\u0026rsquo;essenziale, evitando discussioni infinite e perfezionismo paralizzante.\u003c/p\u003e","title":"Timeboxing"},{"content":"Il transport lag è il ritardo tra il momento in cui il database primary genera un redo log e il momento in cui quel redo log viene ricevuto dal database standby in una configurazione Oracle Data Guard. È uno degli indicatori più importanti per valutare la salute della replica.\nCome si misura #Il transport lag si monitora con una query sulla vista V$DATAGUARD_STATS o tramite Data Guard Broker:\nDGMGRL\u0026gt; SHOW DATABASE 'standby_db' 'TransportLagTarget'; Il valore è espresso in formato tempo (es. +00 00:00:03 = 3 secondi di ritardo). Un transport lag di pochi secondi è normale in modalità Maximum Performance; un lag che cresce costantemente indica un problema di banda o di redo generate rate.\nDifferenza con Apply Lag # Metrica Cosa misura Transport Lag Ritardo nella trasmissione dei redo dal primary allo standby Apply Lag Ritardo nell\u0026rsquo;applicazione dei redo sullo standby dopo la ricezione Il transport lag dipende dalla rete (bandwidth, latenza), l\u0026rsquo;apply lag dipende dalle risorse dello standby (CPU, I/O). Nelle migrazioni cross-site, il transport lag è il collo di bottiglia più comune.\nImpatto nelle migrazioni #Durante una migrazione con Data Guard cross-site, il transport lag va monitorato attentamente durante le fasi di carico massimo (batch notturni, picchi di attività). Un redo generate rate che supera la capacità della VPN produce un transport lag crescente. Prima del cutover, il transport lag deve essere vicino a zero per garantire che lo switchover avvenga senza perdita di dati.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/transport-lag/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003etransport lag\u003c/strong\u003e è il ritardo tra il momento in cui il database primary genera un redo log e il momento in cui quel redo log viene ricevuto dal database standby in una configurazione Oracle Data Guard. È uno degli indicatori più importanti per valutare la salute della replica.\u003c/p\u003e\n\u003ch2 id=\"come-si-misura\" class=\"relative group\"\u003eCome si misura \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-si-misura\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl transport lag si monitora con una query sulla vista \u003ccode\u003eV$DATAGUARD_STATS\u003c/code\u003e o tramite Data Guard Broker:\u003c/p\u003e","title":"Transport Lag"},{"content":"Unified Audit (Oracle Unified Auditing) è il sistema di audit centralizzato introdotto in Oracle Database 12c che sostituisce i meccanismi di audit tradizionali con un\u0026rsquo;unica infrastruttura unificata. Tutti gli eventi di audit convergono nella vista UNIFIED_AUDIT_TRAIL.\nCome funziona #Unified Audit si basa su audit policy: regole dichiarative che specificano quali azioni monitorare (DDL, DML, login, operazioni amministrative). Le policy si creano con CREATE AUDIT POLICY, si attivano con ALTER AUDIT POLICY ... ENABLE e possono essere applicate a utenti specifici o globalmente. I record di audit vengono scritti in una coda interna e poi persistiti nella tabella di sistema.\nA cosa serve #Risponde alla domanda fondamentale della sicurezza: \u0026ldquo;chi ha fatto cosa, quando e da dove?\u0026rdquo; Permette di tracciare operazioni critiche come DROP TABLE, GRANT, REVOKE, accessi a dati sensibili e tentativi di login falliti. È essenziale per la compliance (GDPR, SOX, PCI-DSS) e per le indagini post-incidente.\nPerché è critico #Il vecchio audit tradizionale di Oracle frammentava i log tra file di sistema, tabelle SYS.AUD$ e FGA_LOG$, rendendo l\u0026rsquo;analisi complessa. Unified Audit centralizza tutto in un unico punto, con performance migliori e gestione semplificata. In un ambiente senza audit configurato, un incidente di sicurezza diventa impossibile da ricostruire.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/unified-audit/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eUnified Audit\u003c/strong\u003e (Oracle Unified Auditing) è il sistema di audit centralizzato introdotto in Oracle Database 12c che sostituisce i meccanismi di audit tradizionali con un\u0026rsquo;unica infrastruttura unificata. Tutti gli eventi di audit convergono nella vista \u003ccode\u003eUNIFIED_AUDIT_TRAIL\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eUnified Audit si basa su \u003cstrong\u003eaudit policy\u003c/strong\u003e: regole dichiarative che specificano quali azioni monitorare (DDL, DML, login, operazioni amministrative). Le policy si creano con \u003ccode\u003eCREATE AUDIT POLICY\u003c/code\u003e, si attivano con \u003ccode\u003eALTER AUDIT POLICY ... ENABLE\u003c/code\u003e e possono essere applicate a utenti specifici o globalmente. I record di audit vengono scritti in una coda interna e poi persistiti nella tabella di sistema.\u003c/p\u003e","title":"Unified Audit"},{"content":"Un Unix Socket (o socket di dominio Unix) è un endpoint di comunicazione che permette a due processi sullo stesso sistema operativo di scambiarsi dati senza passare attraverso lo stack di rete TCP/IP. In ambito MySQL, è il metodo di connessione predefinito quando ci si collega a localhost.\nCome funziona #Quando un client MySQL si connette specificando -h localhost, il client non usa TCP. Usa il file socket Unix (tipicamente /var/run/mysqld/mysqld.sock) per comunicare direttamente con il processo del server MySQL. Questa comunicazione avviene interamente nel kernel, senza overhead di rete, ed è più veloce di una connessione TCP anche sullo stesso host.\nA cosa serve #In ambienti multi-istanza, ogni istanza MySQL ha il proprio file socket (es. mysqld.sock, mysqld-app2.sock). Specificare il socket corretto con --socket=/path/to/socket è l\u0026rsquo;unico modo affidabile per connettersi all\u0026rsquo;istanza desiderata. Senza specificare il socket, il client usa quello di default — che quasi sempre punta all\u0026rsquo;istanza primaria.\nQuando si usa #Il socket Unix si usa per tutte le connessioni locali a MySQL. In ambienti con istanze multiple, è essenziale specificare esplicitamente il socket per ogni connessione. Per connessioni remote (da un altro host), si usa invece TCP con -h \u0026lt;ip\u0026gt; -P \u0026lt;porta\u0026gt;.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/unix-socket/","section":"Glossario","summary":"\u003cp\u003eUn \u003cstrong\u003eUnix Socket\u003c/strong\u003e (o socket di dominio Unix) è un endpoint di comunicazione che permette a due processi sullo stesso sistema operativo di scambiarsi dati senza passare attraverso lo stack di rete TCP/IP. In ambito MySQL, è il metodo di connessione predefinito quando ci si collega a \u003ccode\u003elocalhost\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando un client MySQL si connette specificando \u003ccode\u003e-h localhost\u003c/code\u003e, il client non usa TCP. Usa il file socket Unix (tipicamente \u003ccode\u003e/var/run/mysqld/mysqld.sock\u003c/code\u003e) per comunicare direttamente con il processo del server MySQL. Questa comunicazione avviene interamente nel kernel, senza overhead di rete, ed è più veloce di una connessione TCP anche sullo stesso host.\u003c/p\u003e","title":"Unix Socket"},{"content":"VACUUM è il comando PostgreSQL che recupera lo spazio occupato dai dead tuples (righe morte) e lo rende disponibile per nuovi inserimenti. Non restituisce spazio al sistema operativo, non riorganizza la tabella e non compatta nulla — segna le pagine come riscrivibili.\nCome funziona #VACUUM tabella scansiona la tabella, identifica i dead tuples non più visibili a nessuna transazione e ne marca lo spazio come riutilizzabile. È un\u0026rsquo;operazione leggera che non blocca le scritture e può girare in parallelo con le query normali. VACUUM FULL invece riscrive fisicamente l\u0026rsquo;intera tabella con lock esclusivo — da usare rarissimamente e solo in emergenza.\nA cosa serve #Senza VACUUM, le tabelle con alto traffico di UPDATE e DELETE accumulano dead tuples che occupano spazio su disco e rallentano le scansioni sequenziali. Il VACUUM è il meccanismo di pulizia essenziale che bilancia il costo del modello MVCC di PostgreSQL.\nPerché è critico #L\u0026rsquo;autovacuum esegue VACUUM automaticamente, ma con i default di PostgreSQL può attivarsi troppo raramente su tabelle ad alto traffico. Su una tabella con 10 milioni di righe, il default aspetta 2 milioni di dead tuples prima di intervenire — abbastanza per degradare visibilmente le performance.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/vacuum/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eVACUUM\u003c/strong\u003e è il comando PostgreSQL che recupera lo spazio occupato dai dead tuples (righe morte) e lo rende disponibile per nuovi inserimenti. Non restituisce spazio al sistema operativo, non riorganizza la tabella e non compatta nulla — segna le pagine come riscrivibili.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003e\u003ccode\u003eVACUUM tabella\u003c/code\u003e scansiona la tabella, identifica i dead tuples non più visibili a nessuna transazione e ne marca lo spazio come riutilizzabile. È un\u0026rsquo;operazione leggera che non blocca le scritture e può girare in parallelo con le query normali. \u003ccode\u003eVACUUM FULL\u003c/code\u003e invece riscrive fisicamente l\u0026rsquo;intera tabella con lock esclusivo — da usare rarissimamente e solo in emergenza.\u003c/p\u003e","title":"VACUUM"},{"content":"Il Vendor Lock-in è la situazione in cui un\u0026rsquo;azienda diventa dipendente da un fornitore esterno al punto che cambiarlo diventa estremamente costoso o tecnicamente complesso. Nel contesto IT, si verifica quando il codice, l\u0026rsquo;architettura o la conoscenza del sistema sono nelle mani del fornitore e non del cliente.\nCome funziona #Il lock-in si instaura gradualmente: il fornitore scrive il codice con le proprie convenzioni, usa tecnologie proprietarie o non documentate, e il team interno non viene coinvolto nello sviluppo. Quando il fornitore se ne va — per scelta o per licenziamento — porta via con sé il know-how. Il cliente resta con un software che non capisce, non sa manutenere e non può evolvere senza ri-ingaggiare lo stesso fornitore o ricominciare da zero.\nA cosa serve #Comprendere il vendor lock-in è essenziale per prendere decisioni strategiche su outsourcing e sviluppo software. Ogni progetto dovrebbe prevedere misure di mitigazione: documentazione interna, code review, affiancamento del team interno, proprietà del codice sorgente.\nQuando si usa #Il termine descrive un rischio da evitare. Le contromisure principali sono: mantenere il know-how critico internamente, preferire tecnologie open e standard, garantire la proprietà intellettuale del codice, e valutare sempre l\u0026rsquo;opzione \u0026ldquo;buy vs build\u0026rdquo; prima di avviare progetti custom di grande portata.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/vendor-lock-in/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eVendor Lock-in\u003c/strong\u003e è la situazione in cui un\u0026rsquo;azienda diventa dipendente da un fornitore esterno al punto che cambiarlo diventa estremamente costoso o tecnicamente complesso. Nel contesto IT, si verifica quando il codice, l\u0026rsquo;architettura o la conoscenza del sistema sono nelle mani del fornitore e non del cliente.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eIl lock-in si instaura gradualmente: il fornitore scrive il codice con le proprie convenzioni, usa tecnologie proprietarie o non documentate, e il team interno non viene coinvolto nello sviluppo. Quando il fornitore se ne va — per scelta o per licenziamento — porta via con sé il know-how. Il cliente resta con un software che non capisce, non sa manutenere e non può evolvere senza ri-ingaggiare lo stesso fornitore o ricominciare da zero.\u003c/p\u003e","title":"Vendor Lock-in"},{"content":"Il Version Control (controllo versione) è un sistema che registra ogni modifica ai file di un progetto, mantenendo una cronologia completa di chi ha cambiato cosa, quando e perché. Git è il sistema di version control più usato al mondo.\nCome funziona #Ogni modifica viene registrata come \u0026ldquo;commit\u0026rdquo; con un messaggio descrittivo, un autore e un timestamp. Il sistema mantiene l\u0026rsquo;intera storia del progetto: è possibile tornare a qualsiasi versione precedente, confrontare versioni diverse e capire l\u0026rsquo;evoluzione del codice nel tempo. Con Git, ogni sviluppatore ha una copia completa della storia sul proprio computer.\nA cosa serve #Senza version control, il codice vive su cartelle condivise dove le sovrascritture accidentali sono la norma e nessuno sa quale sia la versione \u0026ldquo;buona\u0026rdquo;. Con il version control, ogni modifica è tracciata e reversibile, i conflitti tra sviluppatori vengono gestiti in modo strutturato, e la storia del progetto è una risorsa, non un mistero.\nQuando si usa #Sempre, su qualsiasi progetto software con più di un file o più di uno sviluppatore. L\u0026rsquo;assenza di version control è il primo segnale di un progetto fuori controllo. GitHub, GitLab e Bitbucket sono piattaforme che aggiungono collaborazione (Pull Request, Issue tracker) sopra Git.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/version-control/","section":"Glossario","summary":"\u003cp\u003eIl \u003cstrong\u003eVersion Control\u003c/strong\u003e (controllo versione) è un sistema che registra ogni modifica ai file di un progetto, mantenendo una cronologia completa di chi ha cambiato cosa, quando e perché. Git è il sistema di version control più usato al mondo.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eOgni modifica viene registrata come \u0026ldquo;commit\u0026rdquo; con un messaggio descrittivo, un autore e un timestamp. Il sistema mantiene l\u0026rsquo;intera storia del progetto: è possibile tornare a qualsiasi versione precedente, confrontare versioni diverse e capire l\u0026rsquo;evoluzione del codice nel tempo. Con Git, ogni sviluppatore ha una copia completa della storia sul proprio computer.\u003c/p\u003e","title":"Version Control"},{"content":"Wait Event è un indicatore diagnostico di Oracle Database che identifica il motivo per cui una sessione è in attesa anziché lavorare attivamente. Ogni volta che un processo non può procedere — perché attende un blocco dal disco, un lock, una risposta dalla rete o un turno di CPU — Oracle registra un wait event specifico.\nI più comuni # Wait Event Significato db file sequential read Lettura singolo blocco — tipica di accessi via indice db file scattered read Lettura multi-blocco — tipica di full table scan log file sync Attesa del commit su redo log enq: TX - row lock contention Conflitto su lock di riga direct path read Lettura diretta (bypass buffer cache) A cosa servono #I wait event sono la base della metodologia diagnostica Oracle. Analizzando quali eventi dominano il DB time (tramite AWR o ASH) si identifica immediatamente la natura del problema: I/O, contention, CPU o rete.\nDove si trovano # In tempo reale: V$SESSION_WAIT, V$ACTIVE_SESSION_HISTORY Storici: report AWR (sezione Top Timed Foreground Events), DBA_HIST_ACTIVE_SESS_HISTORY La regola del DBA: non indovinare cosa rallenta il database — guarda i wait event.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/wait-event/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eWait Event\u003c/strong\u003e è un indicatore diagnostico di Oracle Database che identifica il motivo per cui una sessione è in attesa anziché lavorare attivamente. Ogni volta che un processo non può procedere — perché attende un blocco dal disco, un lock, una risposta dalla rete o un turno di CPU — Oracle registra un wait event specifico.\u003c/p\u003e\n\u003ch2 id=\"i-più-comuni\" class=\"relative group\"\u003eI più comuni \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#i-pi%c3%b9-comuni\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eWait Event\u003c/th\u003e\n          \u003cth\u003eSignificato\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003edb file sequential read\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eLettura singolo blocco — tipica di accessi via indice\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003edb file scattered read\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eLettura multi-blocco — tipica di full table scan\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003elog file sync\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eAttesa del commit su redo log\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eenq: TX - row lock contention\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eConflitto su lock di riga\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003edirect path read\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eLettura diretta (bypass buffer cache)\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"a-cosa-servono\" class=\"relative group\"\u003eA cosa servono \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#a-cosa-servono\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eI wait event sono la base della metodologia diagnostica Oracle. Analizzando quali eventi dominano il DB time (tramite AWR o ASH) si identifica immediatamente la natura del problema: I/O, contention, CPU o rete.\u003c/p\u003e","title":"Wait Event"},{"content":"WSREP (Write Set Replication) è l\u0026rsquo;API e il protocollo che Galera Cluster utilizza per la replica sincrona multi-master. Ogni transazione viene catturata come \u0026ldquo;write set\u0026rdquo; (insieme di modifiche a livello di riga) e replicata su tutti i nodi del cluster prima del commit.\nCome funziona #Quando un nodo esegue una transazione, WSREP la intercetta al momento del commit, la impacchetta come write set e la invia a tutti i nodi del cluster tramite il protocollo di comunicazione di gruppo. Ogni nodo esegue un processo di certification: verifica che la transazione non sia in conflitto con altre transazioni concorrenti. Se la certification ha successo, tutti i nodi applicano la transazione. Se fallisce, la transazione viene annullata sul nodo che l\u0026rsquo;ha originata.\nA cosa serve #WSREP garantisce che tutti i nodi del cluster abbiano gli stessi dati in ogni momento (replica sincrona). A differenza della replica asincrona tradizionale di MySQL, non c\u0026rsquo;è ritardo tra master e slave: quando una transazione è committata su un nodo, è già presente su tutti gli altri.\nQuando si usa #WSREP si attiva con il parametro wsrep_on=ON nella configurazione di MariaDB/Percona XtraDB Cluster. Le variabili di stato che iniziano con wsrep_ (come wsrep_cluster_size, wsrep_cluster_status, wsrep_flow_control_paused) sono gli indicatori principali per monitorare la salute del cluster.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/wsrep/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eWSREP\u003c/strong\u003e (Write Set Replication) è l\u0026rsquo;API e il protocollo che Galera Cluster utilizza per la replica sincrona multi-master. Ogni transazione viene catturata come \u0026ldquo;write set\u0026rdquo; (insieme di modifiche a livello di riga) e replicata su tutti i nodi del cluster prima del commit.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando un nodo esegue una transazione, WSREP la intercetta al momento del commit, la impacchetta come write set e la invia a tutti i nodi del cluster tramite il protocollo di comunicazione di gruppo. Ogni nodo esegue un processo di \u003cstrong\u003ecertification\u003c/strong\u003e: verifica che la transazione non sia in conflitto con altre transazioni concorrenti. Se la certification ha successo, tutti i nodi applicano la transazione. Se fallisce, la transazione viene annullata sul nodo che l\u0026rsquo;ha originata.\u003c/p\u003e","title":"WSREP"},{"content":"Yes-And (Sì-E) è una tecnica di comunicazione originaria del teatro di improvvisazione, applicata al project management per trasformare le discussioni conflittuali in conversazioni costruttive. Il principio è semplice: invece di negare la proposta dell\u0026rsquo;interlocutore con \u0026ldquo;No, però\u0026hellip;\u0026rdquo;, si accoglie con \u0026ldquo;Sì, e\u0026hellip;\u0026rdquo; aggiungendo il proprio contributo.\nCome funziona #Quando qualcuno propone un\u0026rsquo;idea, la risposta \u0026ldquo;No\u0026rdquo; attiva una reazione difensiva e blocca la conversazione. La risposta \u0026ldquo;Sì, e\u0026hellip;\u0026rdquo; riconosce la validità della proposta e la estende, mantenendo il dialogo aperto. Non significa essere d\u0026rsquo;accordo su tutto — significa costruire sulla proposta dell\u0026rsquo;altro prima di ridirezionarla.\nQuando si usa #Nelle riunioni di progetto dove due posizioni si scontrano, nelle code review dove il feedback rischia di suonare come critica, nelle negoziazioni con gli stakeholder dove un \u0026ldquo;no\u0026rdquo; secco brucia i rapporti. È particolarmente efficace quando bisogna far convergere opinioni diverse verso una decisione condivisa.\nQuando non funziona #Non si applica a questioni di sicurezza, violazioni di processo o deadline non negoziabili. Se qualcuno propone di rimuovere l\u0026rsquo;autenticazione dal database di produzione, la risposta è \u0026ldquo;No\u0026rdquo;, punto. Il Yes-And funziona con persone in buona fede; non funziona con chi vuole solo avere ragione.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/yes-and/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eYes-And\u003c/strong\u003e (Sì-E) è una tecnica di comunicazione originaria del teatro di improvvisazione, applicata al project management per trasformare le discussioni conflittuali in conversazioni costruttive. Il principio è semplice: invece di negare la proposta dell\u0026rsquo;interlocutore con \u0026ldquo;No, però\u0026hellip;\u0026rdquo;, si accoglie con \u0026ldquo;Sì, e\u0026hellip;\u0026rdquo; aggiungendo il proprio contributo.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eQuando qualcuno propone un\u0026rsquo;idea, la risposta \u0026ldquo;No\u0026rdquo; attiva una reazione difensiva e blocca la conversazione. La risposta \u0026ldquo;Sì, e\u0026hellip;\u0026rdquo; riconosce la validità della proposta e la estende, mantenendo il dialogo aperto. Non significa essere d\u0026rsquo;accordo su tutto — significa costruire sulla proposta dell\u0026rsquo;altro prima di ridirezionarla.\u003c/p\u003e","title":"Yes-And"},{"content":"ZDM (Zero Downtime Migration) è lo strumento che Oracle fornisce per automatizzare le migrazioni di database Oracle verso OCI (Oracle Cloud Infrastructure) o verso database on-premises di versione superiore. Il nome è un po\u0026rsquo; ottimistico — il downtime non è zero, ma è ridotto al minimo.\nCome funziona #ZDM è essenzialmente un orchestratore che combina tecnologie Oracle esistenti sotto un unico flusso automatizzato. Supporta due modalità:\nMigrazione fisica (basata su Data Guard): crea uno standby del database sorgente sulla destinazione, lo sincronizza tramite redo transport, e poi esegue uno switchover. Downtime dell\u0026rsquo;ordine di minuti. Migrazione logica (basata su Data Pump): esegue export e import logico con sincronizzazione incrementale tramite GoldenGate o Data Pump. Più flessibile ma più lenta. Quando usarlo #ZDM è indicato per migrazioni standard dove l\u0026rsquo;infrastruttura sorgente e quella di destinazione sono configurate in modo convenzionale. Il vantaggio è l\u0026rsquo;automazione: riduce la possibilità di errore umano nei passaggi ripetitivi.\nQuando non usarlo #Per configurazioni complesse — RAC con DB link cross-engine, dipendenze esterne non standard, procedure PL/SQL con chiamate HTTP — il layer di automazione di ZDM può diventare un ostacolo. In questi casi, configurare Data Guard manualmente dà più controllo sui dettagli e sulla sequenza delle operazioni.\nRequisiti #ZDM richiede un host dedicato (il \u0026ldquo;ZDM service host\u0026rdquo;) con accesso SSH sia al database sorgente che alla destinazione. Il sorgente deve essere Oracle 11.2.0.4 o superiore, la destinazione può essere su OCI o on-premises.\n","date":"1 gennaio 0001","permalink":"https://ivanluminaria.com/it/glossary/zdm/","section":"Glossario","summary":"\u003cp\u003e\u003cstrong\u003eZDM\u003c/strong\u003e (Zero Downtime Migration) è lo strumento che Oracle fornisce per automatizzare le migrazioni di database Oracle verso OCI (Oracle Cloud Infrastructure) o verso database on-premises di versione superiore. Il nome è un po\u0026rsquo; ottimistico — il downtime non è zero, ma è ridotto al minimo.\u003c/p\u003e\n\u003ch2 id=\"come-funziona\" class=\"relative group\"\u003eCome funziona \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#come-funziona\" aria-label=\"Ancora\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eZDM è essenzialmente un orchestratore che combina tecnologie Oracle esistenti sotto un unico flusso automatizzato. Supporta due modalità:\u003c/p\u003e","title":"ZDM"}]