[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-post-nl-\u002Fblog\u002Fupstreamads-wal-optimization-\u002Fblog\u002Fupstreamads-wal-optimization":3,"blog-post-surround-nl-\u002Fblog\u002Fupstreamads-wal-optimization-\u002Fblog\u002Fupstreamads-wal-optimization":1305,"related-posts-nl-\u002Fblog\u002Fupstreamads-wal-optimization-\u002Fblog\u002Fupstreamads-wal-optimization":1310},{"id":4,"title":5,"authors":6,"badge":13,"body":15,"categories":1288,"date":1290,"description":1291,"extension":1292,"image":1293,"meta":1295,"navigation":363,"path":1296,"readingTime":184,"seo":1297,"stem":1298,"tags":1299,"__hash__":1304},"posts_nl\u002Fblog\u002F9.upstreamads-wal-optimization.md","UpstreamAds: Write Performance Oplossen Met WAL Optimalisatie",[7],{"name":8,"to":9,"avatar":10,"bio":12},"Rob Schoenaker","https:\u002F\u002Flinkedin.com\u002Fin\u002Frobschoenaker",{"src":11},"\u002Fimages\u002Fteam\u002Frob.jpg","Managing Partner bij UpstreamAds en Partner bij Ludulicious B.V. met meer dan 20 jaar ervaring in softwareontwikkeling, gespecialiseerd in .NET Core, ServiceStack, C# en database design.",{"label":14},"Write Performance",{"type":16,"value":17,"toc":1261},"minimark",[18,23,27,33,49,54,90,101,105,108,113,127,131,136,139,188,193,231,237,241,244,249,275,280,294,300,304,307,332,337,385,390,413,418,422,426,429,459,463,466,610,614,628,633,637,641,644,696,700,703,874,878,895,900,904,1007,1011,1015,1026,1030,1041,1045,1056,1060,1071,1075,1086,1090,1093,1164,1168,1171,1174,1177,1197,1202,1210,1248,1251,1257],[19,20,22],"h2",{"id":21},"het-probleem-write-performance-doodt-gebruikerservaring","Het Probleem: Write Performance Doodt Gebruikerservaring",[24,25,26],"p",{},"In 2022 stond UpstreamAds voor een kritieke write performance uitdaging. Adverteerders die nieuwe campagnes aanmaakten wachtten 500ms voordat hun ad creatives werden opgeslagen. Voor een write-heavy applicatie was dit volledig onacceptabel.",[24,28,29],{},[30,31,32],"strong",{},"De Uitdaging:",[34,35,36,40,43,46],"ul",{},[37,38,39],"li",{},"Write-heavy workload met frequente ad creative updates",[37,41,42],{},"Adverteerders verwachten directe save bevestigingen",[37,44,45],{},"WAL configuratie geoptimaliseerd voor betrouwbaarheid, niet performance",[37,47,48],{},"Geen dedicated hardware voor write operaties",[24,50,51],{},[30,52,53],{},"De Cijfers:",[55,56,61],"pre",{"className":57,"code":58,"language":59,"meta":60,"style":60},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","-- Deze INSERT duurde 500+ milliseconden\nINSERT INTO ad_creatives (title, description, status, created_at)\nVALUES ('New Diving Equipment Campaign', 'Amazing diving gear for professionals', 'active', NOW());\n-- Uitvoeringstijd: 500ms per insert\n","sql","",[62,63,64,72,78,84],"code",{"__ignoreMap":60},[65,66,69],"span",{"class":67,"line":68},"line",1,[65,70,71],{},"-- Deze INSERT duurde 500+ milliseconden\n",[65,73,75],{"class":67,"line":74},2,[65,76,77],{},"INSERT INTO ad_creatives (title, description, status, created_at)\n",[65,79,81],{"class":67,"line":80},3,[65,82,83],{},"VALUES ('New Diving Equipment Campaign', 'Amazing diving gear for professionals', 'active', NOW());\n",[65,85,87],{"class":67,"line":86},4,[65,88,89],{},"-- Uitvoeringstijd: 500ms per insert\n",[24,91,92],{},[93,94],"img",{"alt":95,"className":96,"height":98,"src":99,"width":100},"UpstreamAds WAL performance monitoring",[97],"rounded-lg",600,"https:\u002F\u002Fpicsum.photos\u002Fid\u002F11\u002F1000\u002F600",1000,[19,102,104],{"id":103},"de-oorzaak-slechte-wal-configuratie","De Oorzaak: Slechte WAL Configuratie",[24,106,107],{},"Het probleem was duidelijk uit onze monitoring:",[24,109,110],{},[30,111,112],{},"Wat er gebeurde:",[34,114,115,118,121,124],{},[37,116,117],{},"Default WAL instellingen geoptimaliseerd voor betrouwbaarheid, niet performance",[37,119,120],{},"Geen dedicated WAL disk",[37,122,123],{},"Checkpoint instellingen veroorzaakten I\u002FO spikes",[37,125,126],{},"WAL constant achter tijdens piekgebruik",[19,128,130],{"id":129},"de-oplossing-geoptimaliseerde-wal-configuratie","De Oplossing: Geoptimaliseerde WAL Configuratie",[132,133,135],"h3",{"id":134},"stap-1-optimaliseer-wal-instellingen","Stap 1: Optimaliseer WAL Instellingen",[24,137,138],{},"De eerste doorbraak kwam met geoptimaliseerde WAL configuratie:",[55,140,142],{"className":57,"code":141,"language":59,"meta":60,"style":60},"-- Productie WAL instellingen die ons probleem oplosten\nwal_level = replica\nwal_buffers = 16MB                    -- Verhoogd van default 16KB\ncheckpoint_completion_target = 0.9    -- Vloeiendere checkpoints\ncheckpoint_timeout = 15min            -- Minder frequente checkpoints\nmax_wal_size = 4GB                    -- Meer WAL ruimte\nmin_wal_size = 1GB                    -- Snellere recovery\nwal_compression = on                   -- Bespaar disk ruimte\n",[62,143,144,149,154,159,164,170,176,182],{"__ignoreMap":60},[65,145,146],{"class":67,"line":68},[65,147,148],{},"-- Productie WAL instellingen die ons probleem oplosten\n",[65,150,151],{"class":67,"line":74},[65,152,153],{},"wal_level = replica\n",[65,155,156],{"class":67,"line":80},[65,157,158],{},"wal_buffers = 16MB                    -- Verhoogd van default 16KB\n",[65,160,161],{"class":67,"line":86},[65,162,163],{},"checkpoint_completion_target = 0.9    -- Vloeiendere checkpoints\n",[65,165,167],{"class":67,"line":166},5,[65,168,169],{},"checkpoint_timeout = 15min            -- Minder frequente checkpoints\n",[65,171,173],{"class":67,"line":172},6,[65,174,175],{},"max_wal_size = 4GB                    -- Meer WAL ruimte\n",[65,177,179],{"class":67,"line":178},7,[65,180,181],{},"min_wal_size = 1GB                    -- Snellere recovery\n",[65,183,185],{"class":67,"line":184},8,[65,186,187],{},"wal_compression = on                   -- Bespaar disk ruimte\n",[24,189,190],{},[30,191,192],{},"Waarom Deze Instellingen Werken:",[34,194,195,201,207,213,219,225],{},[37,196,197,200],{},[62,198,199],{},"wal_buffers = 16MB",": WAL data wordt gebufferd in geheugen voordat het naar disk wordt geschreven, vermindert I\u002FO operaties",[37,202,203,206],{},[62,204,205],{},"checkpoint_completion_target = 0.9",": Spreidt checkpoint I\u002FO over 90% van het checkpoint interval, voorkomt I\u002FO spikes",[37,208,209,212],{},[62,210,211],{},"checkpoint_timeout = 15min",": Langere intervallen betekenen minder checkpoints, vermindert totale I\u002FO overhead",[37,214,215,218],{},[62,216,217],{},"max_wal_size = 4GB",": Meer WAL ruimte laat PostgreSQL toe checkpoints uit te stellen wanneer systeem druk is",[37,220,221,224],{},[62,222,223],{},"wal_compression = on",": Comprimeert WAL data, vermindert disk I\u002FO en storage vereisten",[37,226,227,230],{},[62,228,229],{},"wal_level = replica",": Schakelt replicatie in maar logt niet elke statement, balanceert performance en functionaliteit",[24,232,233,236],{},[30,234,235],{},"Direct Resultaat:"," Write performance verbeterde van 500ms naar 200ms (2.5x verbetering)",[132,238,240],{"id":239},"stap-2-hardware-investering-voor-wal-performance","Stap 2: Hardware Investering Voor WAL Performance",[24,242,243],{},"De configuratie wijzigingen hielpen, maar hardware optimalisatie was cruciaal:",[24,245,246],{},[30,247,248],{},"De Hardware Investering Die Uitbetaalde:",[34,250,251,257,263,269],{},[37,252,253,256],{},[30,254,255],{},"Battery-backed RAID controller",": Essentieel voor WAL performance",[37,258,259,262],{},[30,260,261],{},"Separate WAL disk",": Dedicated SSD voor WAL bestanden",[37,264,265,268],{},[30,266,267],{},"RAID 1 voor WAL",": Mirroring voor betrouwbaarheid",[37,270,271,274],{},[30,272,273],{},"Snelle SSD storage",": NVMe SSDs voor WAL operaties",[24,276,277],{},[30,278,279],{},"Waarom Deze Hardware Belangrijk Is:",[34,281,282,285,288,291],{},[37,283,284],{},"Battery-backed RAID zorgt voor data integriteit tijdens stroomuitval",[37,286,287],{},"Dedicated WAL disk elimineert I\u002FO contention met data bestanden",[37,289,290],{},"RAID 1 biedt redundantie zonder performance penalty",[37,292,293],{},"NVMe SSDs bieden lage latency, hoge throughput storage",[24,295,296,299],{},[30,297,298],{},"Resultaat:"," Write performance verbeterde naar 150ms (3.3x verbetering)",[132,301,303],{"id":302},"stap-3-connection-pooling-optimalisatie","Stap 3: Connection Pooling Optimalisatie",[24,305,306],{},"Met betere WAL performance werd connection management de bottleneck:",[55,308,310],{"className":57,"code":309,"language":59,"meta":60,"style":60},"-- Connection instellingen optimalisatie\nmax_connections = 200\nshared_preload_libraries = 'pg_stat_statements'\ntrack_activity_query_size = 2048\n",[62,311,312,317,322,327],{"__ignoreMap":60},[65,313,314],{"class":67,"line":68},[65,315,316],{},"-- Connection instellingen optimalisatie\n",[65,318,319],{"class":67,"line":74},[65,320,321],{},"max_connections = 200\n",[65,323,324],{"class":67,"line":80},[65,325,326],{},"shared_preload_libraries = 'pg_stat_statements'\n",[65,328,329],{"class":67,"line":86},[65,330,331],{},"track_activity_query_size = 2048\n",[24,333,334],{},[30,335,336],{},"PgBouncer Gebruiken Voor Connection Pooling:",[55,338,342],{"className":339,"code":340,"language":341,"meta":60,"style":60},"language-ini shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# pgbouncer.ini\n[databases]\nupstreamads = host=localhost port=5432 dbname=upstreamads pool_size=100\n\n[pgbouncer]\npool_mode = transaction\nmax_client_conn = 1000\ndefault_pool_size = 25\n","ini",[62,343,344,349,354,359,365,370,375,380],{"__ignoreMap":60},[65,345,346],{"class":67,"line":68},[65,347,348],{},"# pgbouncer.ini\n",[65,350,351],{"class":67,"line":74},[65,352,353],{},"[databases]\n",[65,355,356],{"class":67,"line":80},[65,357,358],{},"upstreamads = host=localhost port=5432 dbname=upstreamads pool_size=100\n",[65,360,361],{"class":67,"line":86},[65,362,364],{"emptyLinePlaceholder":363},true,"\n",[65,366,367],{"class":67,"line":166},[65,368,369],{},"[pgbouncer]\n",[65,371,372],{"class":67,"line":172},[65,373,374],{},"pool_mode = transaction\n",[65,376,377],{"class":67,"line":178},[65,378,379],{},"max_client_conn = 1000\n",[65,381,382],{"class":67,"line":184},[65,383,384],{},"default_pool_size = 25\n",[24,386,387],{},[30,388,389],{},"Waarom Dit Werkt:",[34,391,392,398,404,410],{},[37,393,394,397],{},[62,395,396],{},"pool_mode = transaction",": Hergebruikt connections over transacties",[37,399,400,403],{},[62,401,402],{},"pool_size = 100",": Onderhoudt 100 persistente connections naar PostgreSQL",[37,405,406,409],{},[62,407,408],{},"max_client_conn = 1000",": Handelt tot 1000 client connections",[37,411,412],{},"Elimineert connection overhead voor frequente writes",[24,414,415,417],{},[30,416,298],{}," Write performance verbeterde naar 120ms (4.2x verbetering)",[19,419,421],{"id":420},"de-game-changer-write-ahead-logging-monitoring","De Game Changer: Write-Ahead Logging Monitoring",[132,423,425],{"id":424},"het-probleem-wal-performance-degradatie","Het Probleem: WAL Performance Degradatie",[24,427,428],{},"Zelfs met optimalisatie was WAL performance inconsistent:",[55,430,432],{"className":57,"code":431,"language":59,"meta":60,"style":60},"-- Probleem: WAL performance varieerde op basis van systeembelasting\nSELECT \n    pg_current_wal_lsn(),\n    pg_walfile_name(pg_current_wal_lsn()),\n    pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), '0\u002F0'));\n",[62,433,434,439,444,449,454],{"__ignoreMap":60},[65,435,436],{"class":67,"line":68},[65,437,438],{},"-- Probleem: WAL performance varieerde op basis van systeembelasting\n",[65,440,441],{"class":67,"line":74},[65,442,443],{},"SELECT \n",[65,445,446],{"class":67,"line":80},[65,447,448],{},"    pg_current_wal_lsn(),\n",[65,450,451],{"class":67,"line":86},[65,452,453],{},"    pg_walfile_name(pg_current_wal_lsn()),\n",[65,455,456],{"class":67,"line":166},[65,457,458],{},"    pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), '0\u002F0'));\n",[132,460,462],{"id":461},"de-oplossing-geautomatiseerde-wal-monitoring","De Oplossing: Geautomatiseerde WAL Monitoring",[24,464,465],{},"We implementeerden uitgebreide WAL monitoring:",[55,467,469],{"className":57,"code":468,"language":59,"meta":60,"style":60},"-- WAL performance monitoring view\nCREATE VIEW wal_performance AS\nSELECT \n    pg_current_wal_lsn() as current_lsn,\n    pg_walfile_name(pg_current_wal_lsn()) as current_wal_file,\n    pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), '0\u002F0')) as wal_size,\n    (SELECT count(*) FROM pg_stat_activity WHERE state = 'active') as active_connections,\n    (SELECT count(*) FROM pg_stat_activity WHERE state = 'idle in transaction') as idle_transactions;\n\n-- Geautomatiseerde WAL maintenance functie\nCREATE OR REPLACE FUNCTION auto_wal_maintenance()\nRETURNS void AS $$\nBEGIN\n    -- Controleer WAL grootte en trigger maintenance indien nodig\n    IF (SELECT pg_wal_lsn_diff(pg_current_wal_lsn(), '0\u002F0')) > 2 * 1024 * 1024 * 1024 THEN\n        PERFORM pg_switch_wal();\n    END IF;\n    \n    -- Update WAL statistieken\n    PERFORM pg_stat_reset();\nEND;\n$$ LANGUAGE plpgsql;\n\n-- Plan WAL maintenance elke 5 minuten\nSELECT cron.schedule('wal-maintenance', '*\u002F5 * * * *', 'SELECT auto_wal_maintenance();');\n",[62,470,471,476,481,485,490,495,500,505,510,515,521,527,533,539,545,551,557,563,569,575,581,587,593,598,604],{"__ignoreMap":60},[65,472,473],{"class":67,"line":68},[65,474,475],{},"-- WAL performance monitoring view\n",[65,477,478],{"class":67,"line":74},[65,479,480],{},"CREATE VIEW wal_performance AS\n",[65,482,483],{"class":67,"line":80},[65,484,443],{},[65,486,487],{"class":67,"line":86},[65,488,489],{},"    pg_current_wal_lsn() as current_lsn,\n",[65,491,492],{"class":67,"line":166},[65,493,494],{},"    pg_walfile_name(pg_current_wal_lsn()) as current_wal_file,\n",[65,496,497],{"class":67,"line":172},[65,498,499],{},"    pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), '0\u002F0')) as wal_size,\n",[65,501,502],{"class":67,"line":178},[65,503,504],{},"    (SELECT count(*) FROM pg_stat_activity WHERE state = 'active') as active_connections,\n",[65,506,507],{"class":67,"line":184},[65,508,509],{},"    (SELECT count(*) FROM pg_stat_activity WHERE state = 'idle in transaction') as idle_transactions;\n",[65,511,513],{"class":67,"line":512},9,[65,514,364],{"emptyLinePlaceholder":363},[65,516,518],{"class":67,"line":517},10,[65,519,520],{},"-- Geautomatiseerde WAL maintenance functie\n",[65,522,524],{"class":67,"line":523},11,[65,525,526],{},"CREATE OR REPLACE FUNCTION auto_wal_maintenance()\n",[65,528,530],{"class":67,"line":529},12,[65,531,532],{},"RETURNS void AS $$\n",[65,534,536],{"class":67,"line":535},13,[65,537,538],{},"BEGIN\n",[65,540,542],{"class":67,"line":541},14,[65,543,544],{},"    -- Controleer WAL grootte en trigger maintenance indien nodig\n",[65,546,548],{"class":67,"line":547},15,[65,549,550],{},"    IF (SELECT pg_wal_lsn_diff(pg_current_wal_lsn(), '0\u002F0')) > 2 * 1024 * 1024 * 1024 THEN\n",[65,552,554],{"class":67,"line":553},16,[65,555,556],{},"        PERFORM pg_switch_wal();\n",[65,558,560],{"class":67,"line":559},17,[65,561,562],{},"    END IF;\n",[65,564,566],{"class":67,"line":565},18,[65,567,568],{},"    \n",[65,570,572],{"class":67,"line":571},19,[65,573,574],{},"    -- Update WAL statistieken\n",[65,576,578],{"class":67,"line":577},20,[65,579,580],{},"    PERFORM pg_stat_reset();\n",[65,582,584],{"class":67,"line":583},21,[65,585,586],{},"END;\n",[65,588,590],{"class":67,"line":589},22,[65,591,592],{},"$$ LANGUAGE plpgsql;\n",[65,594,596],{"class":67,"line":595},23,[65,597,364],{"emptyLinePlaceholder":363},[65,599,601],{"class":67,"line":600},24,[65,602,603],{},"-- Plan WAL maintenance elke 5 minuten\n",[65,605,607],{"class":67,"line":606},25,[65,608,609],{},"SELECT cron.schedule('wal-maintenance', '*\u002F5 * * * *', 'SELECT auto_wal_maintenance();');\n",[24,611,612],{},[30,613,389],{},[34,615,616,619,622,625],{},[37,617,618],{},"Monitort WAL grootte en performance metrics",[37,620,621],{},"Schakelt automatisch WAL bestanden wanneer ze te groot worden",[37,623,624],{},"Reset statistieken om accurate monitoring te behouden",[37,626,627],{},"Draait maintenance tijdens off-peak uren",[24,629,630,632],{},[30,631,298],{}," Consistente write performance van 100ms (5x verbetering)",[19,634,636],{"id":635},"de-finale-optimalisatie-write-batching-strategie","De Finale Optimalisatie: Write Batching Strategie",[132,638,640],{"id":639},"het-probleem-individuele-write-operaties","Het Probleem: Individuele Write Operaties",[24,642,643],{},"Zelfs met geoptimaliseerde WAL waren individuele writes nog steeds langzaam:",[55,645,649],{"className":646,"code":647,"language":648,"meta":60,"style":60},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F Probleem: Individuele writes voor elke ad creative\nforeach (var creative in adCreatives)\n{\n    await _database.ExecuteAsync(\n        \"INSERT INTO ad_creatives (title, description, status) VALUES (@title, @description, @status)\",\n        creative\n    );\n    \u002F\u002F Elke insert duurt 100ms\n}\n","csharp",[62,650,651,656,661,666,671,676,681,686,691],{"__ignoreMap":60},[65,652,653],{"class":67,"line":68},[65,654,655],{},"\u002F\u002F Probleem: Individuele writes voor elke ad creative\n",[65,657,658],{"class":67,"line":74},[65,659,660],{},"foreach (var creative in adCreatives)\n",[65,662,663],{"class":67,"line":80},[65,664,665],{},"{\n",[65,667,668],{"class":67,"line":86},[65,669,670],{},"    await _database.ExecuteAsync(\n",[65,672,673],{"class":67,"line":166},[65,674,675],{},"        \"INSERT INTO ad_creatives (title, description, status) VALUES (@title, @description, @status)\",\n",[65,677,678],{"class":67,"line":172},[65,679,680],{},"        creative\n",[65,682,683],{"class":67,"line":178},[65,684,685],{},"    );\n",[65,687,688],{"class":67,"line":184},[65,689,690],{},"    \u002F\u002F Elke insert duurt 100ms\n",[65,692,693],{"class":67,"line":512},[65,694,695],{},"}\n",[132,697,699],{"id":698},"de-oplossing-batch-write-operaties","De Oplossing: Batch Write Operaties",[24,701,702],{},"We implementeerden batch writing:",[55,704,706],{"className":646,"code":705,"language":648,"meta":60,"style":60},"\u002F\u002F Oplossing: Batch writes voor meerdere ad creatives\npublic async Task\u003Cint> BatchInsertAdCreatives(List\u003CAdCreative> creatives)\n{\n    using var connection = _connectionPool.GetConnection();\n    using var transaction = connection.BeginTransaction();\n    \n    try\n    {\n        \u002F\u002F Gebruik COPY voor bulk inserts\n        using var writer = connection.BeginBinaryImport(\n            \"COPY ad_creatives (title, description, status, created_at) FROM STDIN WITH BINARY\"\n        );\n        \n        foreach (var creative in creatives)\n        {\n            writer.StartRow();\n            writer.Write(creative.Title);\n            writer.Write(creative.Description);\n            writer.Write(creative.Status);\n            writer.Write(DateTime.UtcNow);\n        }\n        \n        writer.Complete();\n        transaction.Commit();\n        \n        return creatives.Count;\n    }\n    catch\n    {\n        transaction.Rollback();\n        throw;\n    }\n}\n",[62,707,708,713,718,722,727,732,736,741,746,751,756,761,766,771,776,781,786,791,796,801,806,811,815,820,825,829,835,841,847,852,858,864,869],{"__ignoreMap":60},[65,709,710],{"class":67,"line":68},[65,711,712],{},"\u002F\u002F Oplossing: Batch writes voor meerdere ad creatives\n",[65,714,715],{"class":67,"line":74},[65,716,717],{},"public async Task\u003Cint> BatchInsertAdCreatives(List\u003CAdCreative> creatives)\n",[65,719,720],{"class":67,"line":80},[65,721,665],{},[65,723,724],{"class":67,"line":86},[65,725,726],{},"    using var connection = _connectionPool.GetConnection();\n",[65,728,729],{"class":67,"line":166},[65,730,731],{},"    using var transaction = connection.BeginTransaction();\n",[65,733,734],{"class":67,"line":172},[65,735,568],{},[65,737,738],{"class":67,"line":178},[65,739,740],{},"    try\n",[65,742,743],{"class":67,"line":184},[65,744,745],{},"    {\n",[65,747,748],{"class":67,"line":512},[65,749,750],{},"        \u002F\u002F Gebruik COPY voor bulk inserts\n",[65,752,753],{"class":67,"line":517},[65,754,755],{},"        using var writer = connection.BeginBinaryImport(\n",[65,757,758],{"class":67,"line":523},[65,759,760],{},"            \"COPY ad_creatives (title, description, status, created_at) FROM STDIN WITH BINARY\"\n",[65,762,763],{"class":67,"line":529},[65,764,765],{},"        );\n",[65,767,768],{"class":67,"line":535},[65,769,770],{},"        \n",[65,772,773],{"class":67,"line":541},[65,774,775],{},"        foreach (var creative in creatives)\n",[65,777,778],{"class":67,"line":547},[65,779,780],{},"        {\n",[65,782,783],{"class":67,"line":553},[65,784,785],{},"            writer.StartRow();\n",[65,787,788],{"class":67,"line":559},[65,789,790],{},"            writer.Write(creative.Title);\n",[65,792,793],{"class":67,"line":565},[65,794,795],{},"            writer.Write(creative.Description);\n",[65,797,798],{"class":67,"line":571},[65,799,800],{},"            writer.Write(creative.Status);\n",[65,802,803],{"class":67,"line":577},[65,804,805],{},"            writer.Write(DateTime.UtcNow);\n",[65,807,808],{"class":67,"line":583},[65,809,810],{},"        }\n",[65,812,813],{"class":67,"line":589},[65,814,770],{},[65,816,817],{"class":67,"line":595},[65,818,819],{},"        writer.Complete();\n",[65,821,822],{"class":67,"line":600},[65,823,824],{},"        transaction.Commit();\n",[65,826,827],{"class":67,"line":606},[65,828,770],{},[65,830,832],{"class":67,"line":831},26,[65,833,834],{},"        return creatives.Count;\n",[65,836,838],{"class":67,"line":837},27,[65,839,840],{},"    }\n",[65,842,844],{"class":67,"line":843},28,[65,845,846],{},"    catch\n",[65,848,850],{"class":67,"line":849},29,[65,851,745],{},[65,853,855],{"class":67,"line":854},30,[65,856,857],{},"        transaction.Rollback();\n",[65,859,861],{"class":67,"line":860},31,[65,862,863],{},"        throw;\n",[65,865,867],{"class":67,"line":866},32,[65,868,840],{},[65,870,872],{"class":67,"line":871},33,[65,873,695],{},[24,875,876],{},[30,877,389],{},[34,879,880,886,889,892],{},[37,881,882,885],{},[62,883,884],{},"COPY"," commando is veel sneller dan individuele INSERTs",[37,887,888],{},"Binary formaat vermindert data transfer overhead",[37,890,891],{},"Single transaction vermindert WAL overhead",[37,893,894],{},"Batch processing vermindert connection overhead",[24,896,897,899],{},[30,898,298],{}," Batch writes verbeterden naar 20ms per creative (25x verbetering voor batches)",[19,901,903],{"id":902},"performance-resultaten-samenvatting","Performance Resultaten Samenvatting",[905,906,907,923],"table",{},[908,909,910],"thead",{},[911,912,913,917,920],"tr",{},[914,915,916],"th",{},"Optimalisatie Stap",[914,918,919],{},"Write Tijd",[914,921,922],{},"Verbetering",[924,925,926,940,953,966,979,992],"tbody",{},[911,927,928,934,937],{},[929,930,931],"td",{},[30,932,933],{},"Origineel (Default WAL)",[929,935,936],{},"500ms",[929,938,939],{},"Baseline",[911,941,942,947,950],{},[929,943,944],{},[30,945,946],{},"Geoptimaliseerde WAL Instellingen",[929,948,949],{},"200ms",[929,951,952],{},"2.5x sneller",[911,954,955,960,963],{},[929,956,957],{},[30,958,959],{},"Hardware Optimalisatie",[929,961,962],{},"150ms",[929,964,965],{},"3.3x sneller",[911,967,968,973,976],{},[929,969,970],{},[30,971,972],{},"Connection Pooling",[929,974,975],{},"120ms",[929,977,978],{},"4.2x sneller",[911,980,981,986,989],{},[929,982,983],{},[30,984,985],{},"WAL Monitoring",[929,987,988],{},"100ms",[929,990,991],{},"5x sneller",[911,993,994,999,1002],{},[929,995,996],{},[30,997,998],{},"Batch Writing",[929,1000,1001],{},"20ms",[929,1003,1004],{},[30,1005,1006],{},"25x sneller",[19,1008,1010],{"id":1009},"belangrijkste-lessen-geleerd","Belangrijkste Lessen Geleerd",[132,1012,1014],{"id":1013},"_1-wal-configuratie-is-kritiek-voor-write-performance","1. WAL Configuratie Is Kritiek Voor Write Performance",[34,1016,1017,1020,1023],{},[37,1018,1019],{},"Default instellingen zijn geoptimaliseerd voor betrouwbaarheid, niet performance",[37,1021,1022],{},"Juiste WAL configuratie kan write performance dramatisch verbeteren",[37,1024,1025],{},"Balanceer betrouwbaarheid met performance op basis van je behoeften",[132,1027,1029],{"id":1028},"_2-hardware-investering-betaalt-zich-uit","2. Hardware Investering Betaalt Zich Uit",[34,1031,1032,1035,1038],{},[37,1033,1034],{},"Battery-backed RAID controllers zijn essentieel voor WAL performance",[37,1036,1037],{},"Dedicated WAL disks elimineren I\u002FO contention",[37,1039,1040],{},"Snelle SSDs bieden de lage latency nodig voor write operaties",[132,1042,1044],{"id":1043},"_3-connection-pooling-vermindert-overhead","3. Connection Pooling Vermindert Overhead",[34,1046,1047,1050,1053],{},[37,1048,1049],{},"PgBouncer elimineert connection overhead voor frequente writes",[37,1051,1052],{},"Transaction-level pooling is ideaal voor write-heavy workloads",[37,1054,1055],{},"Juiste connection limits voorkomen resource uitputting",[132,1057,1059],{"id":1058},"_4-monitoring-voorkomt-performance-degradatie","4. Monitoring Voorkomt Performance Degradatie",[34,1061,1062,1065,1068],{},[37,1063,1064],{},"WAL performance kan over tijd degraderen",[37,1066,1067],{},"Geautomatiseerde monitoring en maintenance voorkomen problemen",[37,1069,1070],{},"Regelmatige statistiek updates behouden accurate monitoring",[132,1072,1074],{"id":1073},"_5-batch-operaties-schalen-beter","5. Batch Operaties Schalen Beter",[34,1076,1077,1080,1083],{},[37,1078,1079],{},"Individuele writes schalen niet goed",[37,1081,1082],{},"Batch operaties verminderen WAL overhead",[37,1084,1085],{},"COPY commando is veel sneller dan individuele INSERTs",[19,1087,1089],{"id":1088},"implementatie-checklist","Implementatie Checklist",[24,1091,1092],{},"Als je vergelijkbare write performance problemen hebt:",[34,1094,1097,1110,1119,1128,1137,1146,1155],{"className":1095},[1096],"contains-task-list",[37,1098,1101,1105,1106,1109],{"className":1099},[1100],"task-list-item",[1102,1103],"input",{"disabled":363,"type":1104},"checkbox"," ",[30,1107,1108],{},"Optimaliseer WAL instellingen",": Configureer voor je workload",[37,1111,1113,1105,1115,1118],{"className":1112},[1100],[1102,1114],{"disabled":363,"type":1104},[30,1116,1117],{},"Investeer in hardware",": Battery-backed RAID, dedicated WAL disk",[37,1120,1122,1105,1124,1127],{"className":1121},[1100],[1102,1123],{"disabled":363,"type":1104},[30,1125,1126],{},"Implementeer connection pooling",": Gebruik PgBouncer voor write-heavy workloads",[37,1129,1131,1105,1133,1136],{"className":1130},[1100],[1102,1132],{"disabled":363,"type":1104},[30,1134,1135],{},"Voeg WAL monitoring toe",": Track performance en automatiseer maintenance",[37,1138,1140,1105,1142,1145],{"className":1139},[1100],[1102,1141],{"disabled":363,"type":1104},[30,1143,1144],{},"Overweeg batch operaties",": Gebruik COPY voor bulk inserts",[37,1147,1149,1105,1151,1154],{"className":1148},[1100],[1102,1150],{"disabled":363,"type":1104},[30,1152,1153],{},"Monitor write performance",": Track responsetijden en resource gebruik",[37,1156,1158,1105,1160,1163],{"className":1157},[1100],[1102,1159],{"disabled":363,"type":1104},[30,1161,1162],{},"Test onder belasting",": Zorg dat performance behouden blijft tijdens piekgebruik",[19,1165,1167],{"id":1166},"samenvatting","Samenvatting",[24,1169,1170],{},"Het optimaliseren van write performance in PostgreSQL vereist een uitgebreide aanpak. Door geoptimaliseerde WAL configuratie, hardware investering, connection pooling, geautomatiseerde monitoring en batch operaties te combineren, bereikten we een 25x performance verbetering voor UpstreamAds write operaties.",[24,1172,1173],{},"De sleutel was begrijpen dat write performance niet alleen gaat over database configuratie—het gaat over het creëren van een compleet systeem geoptimaliseerd voor write-heavy workloads, van hardware tot applicatie code.",[24,1175,1176],{},"Als dit artikel je hielp write performance optimalisatie te begrijpen, kunnen we je helpen deze technieken te implementeren in je eigen applicaties. Bij Ludulicious specialiseren we ons in:",[34,1178,1179,1185,1191],{},[37,1180,1181,1184],{},[30,1182,1183],{},"Write Performance Optimalisatie",": WAL tuning en hardware optimalisatie",[37,1186,1187,1190],{},[30,1188,1189],{},"Database Performance Optimalisatie",": Van langzame queries tot indexering strategieën",[37,1192,1193,1196],{},[30,1194,1195],{},"Custom Development",": Op maat gemaakte oplossingen voor je specifieke use case",[24,1198,1199],{},[30,1200,1201],{},"Klaar om je write performance te optimaliseren?",[24,1203,1204,1209],{},[1205,1206,1208],"a",{"href":1207},"\u002Fcontact","Neem contact op"," voor een gratis consultatie, of bekijk onze andere optimalisatie gidsen:",[34,1211,1212,1218,1224,1230,1236,1242],{},[37,1213,1214],{},[1205,1215,1217],{"href":1216},"\u002Fblog\u002Fpostgresql-performance-strategy","PostgreSQL Performance Tuning: Strategische Lessen uit Productie",[37,1219,1220],{},[1205,1221,1223],{"href":1222},"\u002Fblog\u002Fduikersgids-ruimtelijk-zoeken-optimalisatie","Duikersgids: Hoe Ik Ruimtelijk Zoeken 55x Sneller Maakte",[37,1225,1226],{},[1205,1227,1229],{"href":1228},"\u002Fblog\u002Frijmwoordenboek-fonetische-zoekoptimalisatie","Rijmwoordenboek: Het 3-Seconden Fonetische Zoekprobleem Oplossen",[37,1231,1232],{},[1205,1233,1235],{"href":1234},"\u002Fblog\u002Frijmwoordenboek-caching-optimization","Rijmwoordenboek: Pagina's Onder 15ms Met Betere Caching",[37,1237,1238],{},[1205,1239,1241],{"href":1240},"\u002Fblog\u002Fupstreamads-fulltext-zoekoptimalisatie","UpstreamAds: Van 1.2s naar 35ms Full-Text Zoeken",[37,1243,1244],{},[1205,1245,1247],{"href":1246},"\u002Fblog\u002Fpostgresql-configuratie-optimalisatie","PostgreSQL Configuratie: De Instellingen Die Ertoe Doen",[1249,1250],"hr",{},[24,1252,1253],{},[1254,1255,1256],"em",{},"Deze optimalisatie case study is gebaseerd op echte productie ervaring met UpstreamAds. Alle performance cijfers zijn van echte productie systemen.",[1258,1259,1260],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":60,"searchDepth":74,"depth":74,"links":1262},[1263,1264,1265,1270,1274,1278,1279,1286,1287],{"id":21,"depth":74,"text":22},{"id":103,"depth":74,"text":104},{"id":129,"depth":74,"text":130,"children":1266},[1267,1268,1269],{"id":134,"depth":80,"text":135},{"id":239,"depth":80,"text":240},{"id":302,"depth":80,"text":303},{"id":420,"depth":74,"text":421,"children":1271},[1272,1273],{"id":424,"depth":80,"text":425},{"id":461,"depth":80,"text":462},{"id":635,"depth":74,"text":636,"children":1275},[1276,1277],{"id":639,"depth":80,"text":640},{"id":698,"depth":80,"text":699},{"id":902,"depth":74,"text":903},{"id":1009,"depth":74,"text":1010,"children":1280},[1281,1282,1283,1284,1285],{"id":1013,"depth":80,"text":1014},{"id":1028,"depth":80,"text":1029},{"id":1043,"depth":80,"text":1044},{"id":1058,"depth":80,"text":1059},{"id":1073,"depth":80,"text":1074},{"id":1088,"depth":74,"text":1089},{"id":1166,"depth":74,"text":1167},[1289,14],"Database Optimalisatie","2025-01-17","Leer hoe we PostgreSQL write performance optimaliseerden voor UpstreamAds, waarbij we ad creative save tijden verbeterden van 500ms naar 100ms met WAL configuratie, hardware optimalisatie en connection pooling strategieën.","md",{"src":1294},"https:\u002F\u002Fpicsum.photos\u002Fid\u002F11\u002F640\u002F360",{},"\u002Fblog\u002Fupstreamads-wal-optimization",{"title":5,"description":1291},"blog\u002F9.upstreamads-wal-optimization",[1300,1301,14,959,972,1302,1303],"PostgreSQL","WAL Optimalisatie","Performance Optimalisatie","UpstreamAds","gqt6utxw-puqpTdZYbugNXt87-OKpvila2ZOpNliU94",[1306,1309],{"title":1241,"path":1240,"stem":1307,"description":1308,"children":-1},"blog\u002F8.upstreamads-fulltext-zoekoptimalisatie","Leer hoe we PostgreSQL full-text zoeken optimaliseerden voor UpstreamAds, waardoor zoektijden daalden van 1.2 seconden naar 35ms met pre-computed tsvector indexen, multi-taal strategieën en partiële indexering.",null,[]]