Files
basicBench/038/002.html
2026-02-24 12:28:15 +08:00

66 lines
102 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<html lang=en op=item style><!--
Page saved with SingleFile
url: https://news.ycombinator.com/item?id=47123631
saved date: Tue Feb 24 2026 10:40:40 GMT+0800 (中国标准时间)
--><meta charset=utf-8><meta name=viewport content="width=device-width, initial-scale=1.0"><style>:root{--sf-img-0: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjMyIiB2aWV3Qm94PSIwIDAgMzIgMTYiIHdpZHRoPSIzMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtMiAyNyAxNC0yOSAxNCAyOXoiIGZpbGw9IiM5OTkiLz48L3N2Zz4=")}</style><style>body{font-family:Verdana,Geneva,sans-serif;font-size:10pt;color:#828282}td{font-family:Verdana,Geneva,sans-serif;font-size:10pt;color:#828282}input{font-family:monospace;font-size:10pt}input[type="submit"]{font-family:Verdana,Geneva,sans-serif}textarea{font-family:monospace;font-size:10pt;resize:both}a:link{color:#000000;text-decoration:none}a:visited{color:#828282;text-decoration:none}.default{font-family:Verdana,Geneva,sans-serif;font-size:10pt;color:#828282}.title{font-family:Verdana,Geneva,sans-serif;font-size:10pt;color:#828282;overflow:hidden}.subtext{font-family:Verdana,Geneva,sans-serif;font-size:7pt;color:#828282}.yclinks{font-family:Verdana,Geneva,sans-serif;font-size:8pt;color:#828282}.pagetop{font-family:Verdana,Geneva,sans-serif;font-size:10pt;color:#222222;line-height:12px}.comhead{font-family:Verdana,Geneva,sans-serif;font-size:8pt;color:#828282}.comment{font-family:Verdana,Geneva,sans-serif;font-size:9pt}.hnname{margin-left:1px;margin-right:5px}#hnmain{min-width:796px}.title a{word-break:break-word}.comment a:link,.comment a:visited{text-decoration:underline}.nosee{visibility:hidden;pointer-events:none;cursor:default}.c00,.c00 a:link{color:#000000}.c5a,.c5a a:link,.c5a a:visited{color:#5a5a5a}.c73 a:link,.c73 a:visited{color:#737373}.c82 a:link,.c82 a:visited{color:#828282}.c88 a:link,.c88 a:visited{color:#888888}.c9c a:link,.c9c a:visited{color:#9c9c9c}.cae a:link,.cae a:visited{color:#aeaeae}.cbe a:link,.cbe a:visited{color:#bebebe}.cce a:link,.cce a:visited{color:#cecece}.cdd a:link,.cdd a:visited{color:#dddddd}.pagetop a:visited{color:#000000}.topsel a:link,.topsel a:visited{color:#ffffff}.subtext a:link,.subtext a:visited{color:#828282}.subtext a:hover{text-decoration:underline}.comhead a:link,.subtext a:visited{color:#828282}.comhead a:hover{text-decoration:underline}.hnmore a:link,a:visited{color:#828282}.default p{margin-top:8px;margin-bottom:0px}pre{overflow:auto;padding:2px;white-space:pre-wrap;overflow-wrap:anywhere}pre:hover{overflow:auto}.votearrow{width:10px;height:10px;border:0px;margin:3px 2px 6px;background:var(--sf-img-0),linear-gradient(transparent,transparent) no-repeat;background-size:10px}@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min-device-pixel-ratio:2){.votearrow{background-size:10px;background-image:var(--sf-img-0),linear-gradient(transparent,transparent)}}@media only screen and (min-width:300px) and (max-width:750px){#hnmain{width:100%;min-width:0}body{padding:0;margin:0;width:100%}td{height:inherit!important}.title,.comment{font-size:inherit}span.pagetop{display:block;margin:3px 5px;font-size:12px;line-height:normal}span.pagetop b{display:block;font-size:15px}table.comment-tree .comment a{display:inline-block;max-width:200px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;vertical-align:top}.title{font-size:11pt;line-height:14pt}.subtext{font-size:9pt}.votearrow{transform:scale(1.3,1.3);margin-right:6px}.votelinks{min-width:18px}.votelinks a{display:block;margin-bottom:9px}input[type="text"],textarea{font-size:16px;width:90%}}.comment{max-width:1215px;overflow-wrap:anywhere}@media only screen and (min-width:300px) and (max-width:389px){.comment{max-width:270px;overflow:hidden}}@media only screen and (min-width:390px) and (max-width:509px){.comment{max-width:350px;overflow:hidden}}@media only screen and (min-width:510px) and (max-width:599px){.comment{max-width:460px;overflow:hidden}}@media only screen and (min-width:600px) and (max-width:689px){.comment{max-width:540px;overflow:hidden}}@media only screen and (min-width:690px) and (max-width:809px){.comment{max-width:620px;overflow:hidden}}@media only screen and (min-width:810px) and (max-width:899px){.comment{max-width:730px;overflow:hidden}}@media only screen and (min-width:900px) and (max-width:1079px){.comment{max-width:810px;overflow:hidden}}@media only screen and (min-width:1080px) and (max-width:1169px){.comment{max-width:970px;overflow:hidden}}@media only screen and (min-width:1170px) and (max-width:1259px){.comment{max-width:1050px;overflow:hidden}}@media only screen and (min-width:1260px) and (max-width:1349px){.comment{max-width:1130px;overflow:hidden}}</style><link rel=canonical href="https://news.ycombinator.com/item?id=47123631"><title>Show HN: PgDog Scale Postgres without changing the app | Hacker News</title><meta name=referrer content=no-referrer><link rel=icon href=data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjE4IiB2aWV3Qm94PSI0IDQgMTg4IDE4OCIgd2lkdGg9IjE4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Im00IDRoMTg4djE4OGgtMTg4eiIgZmlsbD0iI2Y2MCIvPjxwYXRoIGQ9Im03My4yNTIxNzU2IDQ1LjAxIDIyLjc0NzgyNDQgNDcuMzkxMzAwODMgMjIuNzQ3ODI0NC00Ny4zOTEzMDA4M2gxOS41NjU2OTYzMWwtMzQuMzIzNTIwNzEgNjQuNDg2NjE0Njh2NDEuNDkzMzg1MzJoLTE1Ljk4di00MS40OTMzODUzMmwtMzQuMzIzNTIwNzEtNjQuNDg2NjE0Njh6IiBmaWxsPSIjZmZmIi8+PC9zdmc+><style>.sf-hidden{display:none!important}</style><meta http-equiv=content-security-policy content="default-src 'none'; font-src 'self' data:; img-src 'self' data:; style-src 'unsafe-inline'; media-src 'self' data:; script-src 'unsafe-inline' data:; object-src 'self' data:; frame-src 'self' data:;"><body><center><table id=hnmain border=0 cellpadding=0 cellspacing=0 width=85% bgcolor=#f6f6ef><tbody><tr><td bgcolor=#ff6600><table border=0 cellpadding=0 cellspacing=0 width=100% style=padding:2px><tbody><tr><td style=width:18px;padding-right:4px><a href=https://news.ycombinator.com/><img src=data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjE4IiB2aWV3Qm94PSI0IDQgMTg4IDE4OCIgd2lkdGg9IjE4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Im00IDRoMTg4djE4OGgtMTg4eiIgZmlsbD0iI2Y2MCIvPjxwYXRoIGQ9Im03My4yNTIxNzU2IDQ1LjAxIDIyLjc0NzgyNDQgNDcuMzkxMzAwODMgMjIuNzQ3ODI0NC00Ny4zOTEzMDA4M2gxOS41NjU2OTYzMWwtMzQuMzIzNTIwNzEgNjQuNDg2NjE0Njh2NDEuNDkzMzg1MzJoLTE1Ljk4di00MS40OTMzODUzMmwtMzQuMzIzNTIwNzEtNjQuNDg2NjE0Njh6IiBmaWxsPSIjZmZmIi8+PC9zdmc+ width=18 height=18 style="border:1px white solid;display:block"></a><td style=line-height:12pt;height:10px><span class=pagetop><b class=hnname><a href=https://news.ycombinator.com/news>Hacker News</a></b><a href=https://news.ycombinator.com/newswelcome.html>welcome</a> | <a href=https://news.ycombinator.com/newest>new</a> | <a href="https://news.ycombinator.com/threads?id=cdostan">threads</a> | <a href=https://news.ycombinator.com/front>past</a> | <a href=https://news.ycombinator.com/newcomments>comments</a> | <a href=https://news.ycombinator.com/ask>ask</a> | <a href=https://news.ycombinator.com/show>show</a> | <a href=https://news.ycombinator.com/jobs>jobs</a> | <a href=https://news.ycombinator.com/submit rel=nofollow>submit</a></span><td style=text-align:right;padding-right:4px><span class=pagetop><a id=me href="https://news.ycombinator.com/user?id=cdostan">cdostan</a> (<span id=karma>1</span>) | <a id=logout rel=nofollow href="https://news.ycombinator.com/logout?auth=025505045d1988297412d0a373394a79fe9ed9d7&amp;goto=item%3Fid%3D47123631">logout</a></span></table><tr style=height:10px><tr id=bigbox><td><table class=fatitem border=0><tbody><tr class="athing submission" id=47123631><td align=right valign=top class=title><span class=rank></span><td valign=top class=votelinks><center><a id=up_47123631 class=clicky href="https://news.ycombinator.com/vote?id=47123631&amp;how=up&amp;auth=a2f89e05f461243c844581bea87ad21be82011e1&amp;goto=item%3Fid%3D47123631"><div class=votearrow title=upvote></div></a></center><td class=title><span class=titleline><a href=https://github.com/pgdogdev/pgdog>Show HN: PgDog Scale Postgres without changing the app</a><span class="sitebit comhead"> (<a href="https://news.ycombinator.com/from?site=github.com/pgdogdev"><span class=sitestr>github.com/pgdogdev</span></a>)</span></span><tr><td colspan=2><td class=subtext><span class=subline><span class=score id=score_47123631>194 points</span> by <a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-23T15:33:24 1771860804"><a href="https://news.ycombinator.com/item?id=47123631">10 hours ago</a></span> <span id=unv_47123631></span> | <a href="https://news.ycombinator.com/hide?id=47123631&amp;auth=a2f89e05f461243c844581bea87ad21be82011e1&amp;goto=item%3Fid%3D47123631">hide</a> | <a href="https://hn.algolia.com/?query=Show%20HN%3A%20PgDog%20%E2%80%93%20Scale%20Postgres%20without%20changing%20the%20app&amp;type=story&amp;dateRange=all&amp;sort=byDate&amp;storyText=false&amp;prefix&amp;page=0" class=hnpast>past</a> | <a href="https://news.ycombinator.com/fave?id=47123631&amp;auth=a2f89e05f461243c844581bea87ad21be82011e1">favorite</a> | <a href="https://news.ycombinator.com/item?id=47123631">44&nbsp;comments</a></span><tr><td colspan=2><td><div class=toptext style=margin-top:4px>Hey HN! Lev and Justin here, authors of PgDog (<a href=https://pgdog.dev/>https://pgdog.dev/</a>), a connection pooler, load balancer and database sharder for PostgreSQL. If you build apps with a lot of traffic, you know the first thing to break is the database. We are solving this with a network proxy that works without requiring application code changes or database migrations.<p>Our post from last year: <a href="https://news.ycombinator.com/item?id=44099187">https://news.ycombinator.com/item?id=44099187</a><p>The most important update: we are in production. Sharding is used a lot, with direct-to-shard queries (one shard per query) working pretty much all the time. Cross-shard (or multi-database) queries are still a work in progress, but we are making headway.<p>Aggregate functions like count(), min(), max(), avg(), stddev() and variance() are working, without refactoring the app. PgDog calculates the aggregate in-transit, while transparently rewriting queries to fetch any missing info. For example, multi-database average calculation requires a total count of rows to calculate the original sum. PgDog will add count() to the query, if its not there already, and remove it from the rows sent to the app.<p>Sorting and grouping works, including DISTINCT, if the columns(s) are referenced in the result. Over 10 data types are supported, like, timestamp(tz), all integers, varchar, etc.<p>Cross-shard writes, including schema changes (CREATE/DROP/ALTER), are now atomic and synchronized between all shards with two-phase commit. PgDog keeps track of the transaction state internally and will rollback the transaction if the first phase fails. You dont need to monkeypatch your ORM to use this: PgDog will intercept the COMMIT statement and execute PREPARE TRANSACTION and COMMIT PREPARED instead.<p>Omnisharded tables, a.k.a replicated or mirrored (identical on all shards), support atomic reads and writes. Thats important because most databases cant be completely sharded and will have some common data on all databases that has to be kept in-sync.<p>Multi-tuple inserts, e.g., INSERT INTO table_x VALUES ($1, $2), ($3, $4), are split by our query rewriter and distributed to their respective shards automatically. They are used by ORMs like Prisma, Sequelize, and others, so those now work without code changes too.<p>Sharding keys can be mutated. PgDog will intercept and rewrite the update statement into 3 queries, SELECT, INSERT, and DELETE, moving the row between shards. If youre using Citus (for everyone else, Citus is a Postgres extension for sharding databases), this might be worth a look.<p>If youre like us and prefer integers to UUIDs for your primary keys, we built a cross-shard unique sequence, directly inside PgDog. It uses the system clock (and a couple other inputs), can be called like a Postgres function, and will automatically inject values into queries, so ORMs like ActiveRecord will continue to work out of the box. Its monotonically increasing, just like a real Postgres sequence, and can generate up to 4 million numbers per second with a range of 69.73 years, so no need to migrate to UUIDv7 just yet.<p><pre><code> INSERT INTO my_table (id, created_at) VALUES (pgdog.unique_id(), now());
</code></pre>
Resharding is now built-in. We can move gigabytes of tables per second, by parallelizing logical replication streams across replicas. This is really cool! Last time we tried this at Instacart, it took over two weeks to move 10 TB between two machines. Now, we can do this in just a few hours, in big part thanks to the work of the core team that added support for logical replication slots to streaming replicas in Postgres 16.<p>Sharding hardly works without a good load balancer. PgDog can monitor replicas and move write traffic to a promoted primary during a failover. This works with managed Postgres, like RDS (incl. Aurora), Azure Pg, GCP Cloud SQL, etc., because it just polls each instance with “SELECT pg_is_in_recovery()”. Primary election is not supported yet, so if youre self-hosting with Patroni, you should keep it around for now, but you dont need to run HAProxy in front of the DBs anymore.<p>The load balancer is getting pretty smart and can handle edge cases like SELECT FOR UPDATE and CTEs with INSERT/UPDATE statements, but if you still prefer to handle your read/write separation in code, you can do that too with manual routing. This works by giving PgDog a hint at runtime: a connection parameter (-c pgdog.role=primary), SET statement, or a query comment. If you have multiple connection pools in your app, you can replace them with just one connection to PgDog instead. For multi-threaded Python/Ruby/Go apps, this helps by reducing memory usage, I/O and context switching overhead.<p>Speaking of connection pooling, PgDog can automatically rollback unfinished transactions and drain and re-sync partially sent queries, all in an effort to preserve connections to the database. If youve seen Postgres go to 100% CPU because of a connection storm caused by an application crash, this might be for you. Draining connections works by receiving and discarding rows from abandoned queries and sending the Sync message via the Postgres wire protocol, which clears the query context and returns the connection to a normal state.<p>PgDog is open source and welcomes contributions and feedback in any form. As always, all features are configurable and can be turned off/on, so should you choose to give it a try, you can do so at your own pace. Our docs (<a href=https://docs.pgdog.dev/>https://docs.pgdog.dev</a>) should help too.<p>Thanks for reading and happy hacking!</p></div><tr style=height:6px><tr><td colspan=2><td><form action=comment method=post><textarea name=text rows=8 cols=80 wrap=virtual style=vertical-align:bottom></textarea>&nbsp;<a href=https://news.ycombinator.com/formatdoc tabindex=-1><font size=-2 color=#AFAFAF>help</font></a><br><br>
If you haven't already, would you mind reading about HN's <a href=https://news.ycombinator.com/newswelcome.html><u>approach to comments</u></a> and <a href=https://news.ycombinator.com/newsguidelines.html#comments><u>site guidelines</u></a>?<br><br>
<input type=submit value="add comment"></form></table><br>
<table border=0 class=comment-tree><tbody><tr class="coll athing comtr" id=47127202><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class="nosee votelinks"><center><a id=up_47127202 class=clicky href="https://news.ycombinator.com/vote?id=47127202&amp;how=up&amp;auth=47efef5c025eaf76fa16a360f28d24aaaca7d20f&amp;goto=item%3Fid%3D47123631#47127202"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=saisrirampur" class=hnuser>saisrirampur</a> <span class=age title="2026-02-23T19:11:23 1771873883"><a href="https://news.ycombinator.com/item?id=47127202">7 hours ago</a></span> <span id=unv_47127202></span><span class=navs> | <a href=#47126921 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47127202 n=1 href=javascript:void(0)>[1 more]</a><span class=onstory></span></span></span></div><br>
<div class="noshow comment sf-hidden"></div></table><tr class="coll athing comtr" id=47126921><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class="nosee votelinks"><center><a id=up_47126921 class=clicky href="https://news.ycombinator.com/vote?id=47126921&amp;how=up&amp;auth=6fb2f17835baf3ab8db082ba322c87c1a159dfdb&amp;goto=item%3Fid%3D47123631#47126921"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=codegeek" class=hnuser>codegeek</a> <span class=age title="2026-02-23T18:54:49 1771872889"><a href="https://news.ycombinator.com/item?id=47126921">7 hours ago</a></span> <span id=unv_47126921></span><span class=navs> | <a href=#47127202 class=clicky aria-hidden=true>prev</a> | <a href=#47127712 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47126921 n=3 href=javascript:void(0)>[3 more]</a><span class=onstory></span></span></span></div><br>
<div class="noshow comment sf-hidden"></div></table><tr class="noshow athing comtr sf-hidden" id=47126992><tr class="noshow athing comtr sf-hidden" id=47127025><tr class="athing comtr" id=47127712><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class=votelinks><center><a id=up_47127712 class=clicky href="https://news.ycombinator.com/vote?id=47127712&amp;how=up&amp;auth=f09ede49d5e999363187e3e934777daaf76fd9cc&amp;goto=item%3Fid%3D47123631#47127712"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=cuu508" class=hnuser>cuu508</a> <span class=age title="2026-02-23T19:46:45 1771876005"><a href="https://news.ycombinator.com/item?id=47127712">6 hours ago</a></span> <span id=unv_47127712></span><span class=navs> | <a href=#47126921 class=clicky aria-hidden=true>prev</a> | <a href=#47125519 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47127712 n=2 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">Some HTTP proxies can do retries -- if a connection to one backend fails, it is retried on a different backend. Can PgDog (or PgBouncer, or any other tool) do something similar -- if there's a "database server shutting down" error or a connection reset, retry it on another backend?</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47127712&amp;goto=item%3Fid%3D47123631%2347127712" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47128217><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47128217 class=clicky href="https://news.ycombinator.com/vote?id=47128217&amp;how=up&amp;auth=f4becbc6d4dd647cfc538edcc441e0b96243ee9b&amp;goto=item%3Fid%3D47123631#47128217"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-23T20:22:02 1771878122"><a href="https://news.ycombinator.com/item?id=47128217">6 hours ago</a></span> <span id=unv_47128217></span><span class=navs> | <a href=#47127712 class=clicky aria-hidden=true>parent</a> | <a href=#47125519 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47128217 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">Not currently, but we can add this. One thing we have to be careful of is to not retry requests that are executing inside transactions, but otherwise this would be a great feature.</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47128217&amp;goto=item%3Fid%3D47123631%2347128217" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47125519><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class=votelinks><center><a id=up_47125519 class=clicky href="https://news.ycombinator.com/vote?id=47125519&amp;how=up&amp;auth=9d0e6a32d79bc5e9f0927b0d9b91d081ae281799&amp;goto=item%3Fid%3D47123631#47125519"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=mijoharas" class=hnuser>mijoharas</a> <span class=age title="2026-02-23T17:29:17 1771867757"><a href="https://news.ycombinator.com/item?id=47125519">9 hours ago</a></span> <span id=unv_47125519></span><span class=navs> | <a href=#47127712 class=clicky aria-hidden=true>prev</a> | <a href=#47131119 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47125519 n=2 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">Happy pgdog user here, I can recommend it from a user perspective as a connection pooler to anyone checking this out (we're also running tests and positive about sharding, but haven't run it in prod yet, so I can't 100% vouch for it on that, but that's where we're headed.)<p>@Lev, how is the 2pc coming along? I think it was pretty new when I last checked, and I haven't looked into it much since then. Is it feeling pretty solid now?</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47125519&amp;goto=item%3Fid%3D47123631%2347125519" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47125812><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47125812 class=clicky href="https://news.ycombinator.com/vote?id=47125812&amp;how=up&amp;auth=a0091e5e4801d8fab950d818e5a5b0a650d31215&amp;goto=item%3Fid%3D47123631#47125812"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-23T17:47:31 1771868851"><a href="https://news.ycombinator.com/item?id=47125812">8 hours ago</a></span> <span id=unv_47125812></span><span class=navs> | <a href=#47125519 class=clicky aria-hidden=true>parent</a> | <a href=#47131119 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47125812 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">It feels better now, but we still need to add crash protection - in case PgDog itself crashes, we need to restore in-progress 2pc transaction records from a durable medium. We will add this very soon.</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47125812&amp;goto=item%3Fid%3D47123631%2347125812" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47131119><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class=votelinks><center><a id=up_47131119 class=clicky href="https://news.ycombinator.com/vote?id=47131119&amp;how=up&amp;auth=5577feb0b22f2d811219bb0220c7e56a30359e72&amp;goto=item%3Fid%3D47123631#47131119"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=written-beyond" class=hnuser>written-beyond</a> <span class=age title="2026-02-24T00:27:11 1771892831"><a href="https://news.ycombinator.com/item?id=47131119">2 hours ago</a></span> <span id=unv_47131119></span><span class=navs> | <a href=#47125519 class=clicky aria-hidden=true>prev</a> | <a href=#47130616 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47131119 n=2 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">Can you elaborate a bit more on the challenges faced in making Postgres shard-able?<p>I remember that adding sharing to Postgres natively was an uphill battle. There were a few companies who has proprietary solutions for it. What you've been able to achieve is nothing less than a miracle.</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47131119&amp;goto=item%3Fid%3D47123631%2347131119" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47131464><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47131464 class=clicky href="https://news.ycombinator.com/vote?id=47131464&amp;how=up&amp;auth=bee9160f85f004c4dc4098b5debe476956cc496f&amp;goto=item%3Fid%3D47123631#47131464"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-24T01:04:55 1771895095"><a href="https://news.ycombinator.com/item?id=47131464">1 hour ago</a></span> <span id=unv_47131464></span><span class=navs> | <a href=#47131119 class=clicky aria-hidden=true>parent</a> | <a href=#47130616 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47131464 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">So many, where to begin.<p>1. People don't design schemas to be sharded, although many gravitate towards a common key, e.g. user_id or country_id or tenant_it or customer_id. Once that happens, sharding becomes easier.<p>2. Postgres provides a lot of guarantees that are tricky to maintain when sharded: atomic changes, referential integrity, check constraints, unique indexes (and constraints), to name a few. Those have to be built separately by a sharding layer (like PgDog) and have trade-offs, usually around performance. It's a lot more expensive to check a globally enforced constraint than a local one (network hops aren't free).<p>3. Online migrations from unsharded to sharded can be tricky: you have to redistribute terabytes of data while the DB continues to serve writes. You can't lose a single row - Postgres is used as a store of record and this can be a serious issue with business impact.<p>We're taking increasingly bigger bites at this apple. We started with basic query routing and are now doing query rewrites as well. We didn't handle data movements previously and now have almost fully automatic resharding. It takes time, elbow grease and most importantly, willing and courageous early adopters to whom we owe a huge debt of gratitude.</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47131464&amp;goto=item%3Fid%3D47123631%2347131464" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47130616><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class=votelinks><center><a id=up_47130616 class=clicky href="https://news.ycombinator.com/vote?id=47130616&amp;how=up&amp;auth=5660154dcaa593eed52200c80e2ad01417af3199&amp;goto=item%3Fid%3D47123631#47130616"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=lordofgibbons" class=hnuser>lordofgibbons</a> <span class=age title="2026-02-23T23:33:13 1771889593"><a href="https://news.ycombinator.com/item?id=47130616">3 hours ago</a></span> <span id=unv_47130616></span><span class=navs> | <a href=#47131119 class=clicky aria-hidden=true>prev</a> | <a href=#47131018 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47130616 n=2 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">This looks great! I have a couple of questions:<p>1) Is it possible to start off with plain Postgres and add pgdog without scheduled downtime down the road when scaling via sharding becomes necessary?<p>2) How are schema updates handled when using physical multi-tenancy? Does pgdog just loop over all the databases that it knows about and issues the update schema command to each?</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47130616&amp;goto=item%3Fid%3D47123631%2347130616" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47130675><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47130675 class=clicky href="https://news.ycombinator.com/vote?id=47130675&amp;how=up&amp;auth=26b70908ce9682f6aeda513e97ceac0ae4af6777&amp;goto=item%3Fid%3D47123631#47130675"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-23T23:39:25 1771889965"><a href="https://news.ycombinator.com/item?id=47130675">2 hours ago</a></span> <span id=unv_47130675></span><span class=navs> | <a href=#47130616 class=clicky aria-hidden=true>parent</a> | <a href=#47131018 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47130675 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">1. Yup, we support online resharding, so you don't need to deploy this until you have to.<p>2. That's right, we broadcast the DDL to all shards in the configuration. If two-phase commit [1] is enabled, you have a strong guarantee that this operation will be atomic. The broadcast is done in parallel, so this is fast.<p>[1]: <a href=https://docs.pgdog.dev/features/sharding/2pc/>https://docs.pgdog.dev/features/sharding/2pc/</a></p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47130675&amp;goto=item%3Fid%3D47123631%2347130675" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47131018><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class=votelinks><center><a id=up_47131018 class=clicky href="https://news.ycombinator.com/vote?id=47131018&amp;how=up&amp;auth=0a47a21ba28ac6093b6d9de5b28cd487f64e610e&amp;goto=item%3Fid%3D47123631#47131018"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=farsa" class=hnuser>farsa</a> <span class=age title="2026-02-24T00:15:38 1771892138"><a href="https://news.ycombinator.com/item?id=47131018">2 hours ago</a></span> <span id=unv_47131018></span><span class=navs> | <a href=#47130616 class=clicky aria-hidden=true>prev</a> | <a href=#47131282 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47131018 n=2 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">Congrats on the progress!
What is the behavior of PgDoc if it receives some sort of query it can't currently handle properly? Is there a linter/static analysis tool I can use to evaluate if my query will work?</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47131018&amp;goto=item%3Fid%3D47123631%2347131018" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47131554><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47131554 class=clicky href="https://news.ycombinator.com/vote?id=47131554&amp;how=up&amp;auth=f0a4c7aa55ec1507c9d692ebb657c7432d8a32d0&amp;goto=item%3Fid%3D47123631#47131554"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-24T01:13:49 1771895629"><a href="https://news.ycombinator.com/item?id=47131554">1 hour ago</a></span> <span id=unv_47131554></span><span class=navs> | <a href=#47131018 class=clicky aria-hidden=true>parent</a> | <a href=#47131282 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47131554 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">The current behavior unfortunately is to just let it through and return an incorrect result. We are adding more checks here and rely heavily on early adopters to have a decent test suite before launching their apps to prod.<p>That being said, we do have this [1]:<p><pre><code> [general]
expanded_explain = true
</code></pre>
This will modify the output of EXPLAIN queries to return routing decisions made by PgDog. If you see that your query is "direct-to-shard", i.e. goes to only one shard, you can be certain that it'll work as expected. These queries will talk to only one database and don't require us to manipulate the result or assemble results from multiple shards.<p>For cross-shard queries, you'll need your own integration tests, for now. We'll add checks here shortly. We have a decent CI suite as well, but it doesn't cover everything. Every time we look at that part of the code, we just end up adding more features, like the recent support for LIMIT x OFFSET y (PgDog rewrites it to LIMIT x + y and applies the offset calculation in memory).<p>We'll get there.<p>[1]: <a href=https://docs.pgdog.dev/features/sharding/explain/>https://docs.pgdog.dev/features/sharding/explain/</a></p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47131554&amp;goto=item%3Fid%3D47123631%2347131554" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47131282><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class=votelinks><center><a id=up_47131282 class=clicky href="https://news.ycombinator.com/vote?id=47131282&amp;how=up&amp;auth=93fd9652ed53fde709352bf9d8dec4126227a1ac&amp;goto=item%3Fid%3D47123631#47131282"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=ijustlovemath" class=hnuser>ijustlovemath</a> <span class=age title="2026-02-24T00:42:48 1771893768"><a href="https://news.ycombinator.com/item?id=47131282">1 hour ago</a></span> <span id=unv_47131282></span><span class=navs> | <a href=#47131018 class=clicky aria-hidden=true>prev</a> | <a href=#47128494 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47131282 n=2 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">How would this product compare to a PostgREST based approach (this is the cool tech behind the original supabase) with load balancing at the HTTP level?</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47131282&amp;goto=item%3Fid%3D47123631%2347131282" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47131417><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47131417 class=clicky href="https://news.ycombinator.com/vote?id=47131417&amp;how=up&amp;auth=b4d7430cd729e88ab5843cb4901c026cbf0fc04e&amp;goto=item%3Fid%3D47123631#47131417"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-24T00:58:51 1771894731"><a href="https://news.ycombinator.com/item?id=47131417">1 hour ago</a></span> <span id=unv_47131417></span><span class=navs> | <a href=#47131282 class=clicky aria-hidden=true>parent</a> | <a href=#47128494 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47131417 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">PostgREST is a translation layer: you use HTTP methods, inputs and outputs, to interact with Postgres, the database. It's a replacement for SQL, the language, which happens to also have a load balancer.<p>Their load balancer is still at the Postgres layer though. You can think of it as just an application that happens to speak a specific API. Load balancing applications is a solved problem.</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47131417&amp;goto=item%3Fid%3D47123631%2347131417" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47128494><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class=votelinks><center><a id=up_47128494 class=clicky href="https://news.ycombinator.com/vote?id=47128494&amp;how=up&amp;auth=283573f2de7e1fbb0d928ee22779417fd088756b&amp;goto=item%3Fid%3D47123631#47128494"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=mosselman" class=hnuser>mosselman</a> <span class=age title="2026-02-23T20:41:40 1771879300"><a href="https://news.ycombinator.com/item?id=47128494">5 hours ago</a></span> <span id=unv_47128494></span><span class=navs> | <a href=#47131282 class=clicky aria-hidden=true>prev</a> | <a href=#47126391 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47128494 n=4 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">I see the word 'replication' mentioned quite a few times. Is this managed by pgdog? Would I be able to replace other logical replication setups with pgdog to create a High Availability cluster?<p>Do you have any write up on how to do this?</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47128494&amp;goto=item%3Fid%3D47123631%2347128494" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47128637><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47128637 class=clicky href="https://news.ycombinator.com/vote?id=47128637&amp;how=up&amp;auth=db911705873bf47958d5143d55c7f4bc108ad21d&amp;goto=item%3Fid%3D47123631#47128637"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-23T20:53:50 1771880030"><a href="https://news.ycombinator.com/item?id=47128637">5 hours ago</a></span> <span id=unv_47128637></span><span class=navs> | <a href=#47128494 class=clicky aria-hidden=true>parent</a> | <a href=#47126391 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47128637 n=3 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">I'll need a bit more info about your use case to answer. We use logical replication to move data between shards, with the intention of creating new shards.<p>This is managed by PgDog. We are building a lot of tooling here, and a lot of it is configurable and can be used separately. For example, we have a CLI and admin database commands to setup replication streams between databases, irrespective of their sharded status, so it can be used for other purposes as well, like moving tables or entire databases to new hardware. If you keep the stream(s) running, you can effectively keep up-to-date logical replicas.<p>We don't currently manage DDL replication (CREATE/ALTER/DROP) for logically replicated databases - this is a known limitation that we will address shortly. After all, we don't want users to pause schema migrations during resharding. I think once that piece is in, you'll be able to run pretty much any kind of long-lived logical replicas for any purpose, including HA.</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47128637&amp;goto=item%3Fid%3D47123631%2347128637" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47129531><td><table border=0><tbody><tr><td class=ind indent=2><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=80><td valign=top class=votelinks><center><a id=up_47129531 class=clicky href="https://news.ycombinator.com/vote?id=47129531&amp;how=up&amp;auth=8b2e4764dd1ed03abae03002a028e68efed04509&amp;goto=item%3Fid%3D47123631#47129531"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=mosselman" class=hnuser>mosselman</a> <span class=age title="2026-02-23T21:56:09 1771883769"><a href="https://news.ycombinator.com/item?id=47129531">4 hours ago</a></span> <span id=unv_47129531></span><span class=navs> | <a href=#47128494 class=clicky aria-hidden=true>root</a> | <a href=#47128637 class=clicky aria-hidden=true>parent</a> | <a href=#47126391 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47129531 n=2 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">Thanks for the explanation. My use case is replacing patroni with pgdog. DDL replication would be required for this.<p>Is there some way I can get updates about pgdog and especially when the replication you mentioned is there?</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47129531&amp;goto=item%3Fid%3D47123631%2347129531" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47129978><td><table border=0><tbody><tr><td class=ind indent=3><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=120><td valign=top class=votelinks><center><a id=up_47129978 class=clicky href="https://news.ycombinator.com/vote?id=47129978&amp;how=up&amp;auth=ba757df6383c295330220f51f2c08e3d804efe0f&amp;goto=item%3Fid%3D47123631#47129978"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-23T22:36:16 1771886176"><a href="https://news.ycombinator.com/item?id=47129978">4 hours ago</a></span> <span id=unv_47129978></span><span class=navs> | <a href=#47128494 class=clicky aria-hidden=true>root</a> | <a href=#47129531 class=clicky aria-hidden=true>parent</a> | <a href=#47126391 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47129978 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">Absolutely. We do weekly releases here: <a href=https://github.com/pgdogdev/pgdog/releases rel=nofollow>https://github.com/pgdogdev/pgdog/releases</a>. Each release includes a detailed changelog.<p>I believe you can use an RSS reader if those are still in vogue, e.g.: <a href=https://github.com/pgdogdev/pgdog/releases.atom rel=nofollow>https://github.com/pgdogdev/pgdog/releases.atom</a>.</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47129978&amp;goto=item%3Fid%3D47123631%2347129978" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47126391><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class=votelinks><center><a id=up_47126391 class=clicky href="https://news.ycombinator.com/vote?id=47126391&amp;how=up&amp;auth=c68e1012266ef462dc483b0bec92cefbcbcfe050&amp;goto=item%3Fid%3D47123631#47126391"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=noleary" class=hnuser>noleary</a> <span class=age title="2026-02-23T18:19:45 1771870785"><a href="https://news.ycombinator.com/item?id=47126391">8 hours ago</a></span> <span id=unv_47126391></span><span class=navs> | <a href=#47128494 class=clicky aria-hidden=true>prev</a> | <a href=#47126668 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47126391 n=4 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">&gt; If you build apps with a lot of traffic, you know the first thing to break is the database.<p>Just out of curiosity, what kinds of high-traffic apps have been most interested in using PgDog? I see you guys have Coinbase and Ramp logos on your homepage -- seems like fintech is a fit?</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47126391&amp;goto=item%3Fid%3D47123631%2347126391" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47126617><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47126617 class=clicky href="https://news.ycombinator.com/vote?id=47126617&amp;how=up&amp;auth=649d7cf8398c2b1ce0a840f42c8c83418d14df09&amp;goto=item%3Fid%3D47123631#47126617"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-23T18:33:48 1771871628"><a href="https://news.ycombinator.com/item?id=47126617">8 hours ago</a></span> <span id=unv_47126617></span><span class=navs> | <a href=#47126391 class=clicky aria-hidden=true>parent</a> | <a href=#47126668 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47126617 n=3 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">We have all kinds, it's not specific to any particular sector. That's kind of the beauty for building for Postgres - everyone uses it in some capacity!<p>My general advice is, once you see more than 100 connections on your database, you should consider adding a connection pooler. If your primary load exceeds 30% (CPU util), consider adding read replicas. This also applies if you want some kind of workload isolation between databases, e.g. slow/expensive analytics queries can be pushed to a replica. Vertically scaling primaries is also a fine choice, just keep that vertical limit in mind.<p>Once you're a couple instance types away from the largest machine your cloud provider has, start thinking about sharding.</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47126617&amp;goto=item%3Fid%3D47123631%2347126617" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47126875><td><table border=0><tbody><tr><td class=ind indent=2><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=80><td valign=top class=votelinks><center><a id=up_47126875 class=clicky href="https://news.ycombinator.com/vote?id=47126875&amp;how=up&amp;auth=e37f34ca4b307b9273231c0308a4d7fb9f5f73d2&amp;goto=item%3Fid%3D47123631#47126875"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=mystifyingpoi" class=hnuser>mystifyingpoi</a> <span class=age title="2026-02-23T18:51:10 1771872670"><a href="https://news.ycombinator.com/item?id=47126875">7 hours ago</a></span> <span id=unv_47126875></span><span class=navs> | <a href=#47126391 class=clicky aria-hidden=true>root</a> | <a href=#47126617 class=clicky aria-hidden=true>parent</a> | <a href=#47126668 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47126875 n=2 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">&gt; If your primary load exceeds 30% (CPU util), consider adding read replicas.<p>I'm not an expert, but isn't this excessive? In theory you could triple the load and still have slack. I'd actually try to scale down, not up.</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47126875&amp;goto=item%3Fid%3D47123631%2347126875" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47127844><td><table border=0><tbody><tr><td class=ind indent=3><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=120><td valign=top class=votelinks><center><a id=up_47127844 class=clicky href="https://news.ycombinator.com/vote?id=47127844&amp;how=up&amp;auth=32f1a0ef9aa16382009b9e0b5eff44a55706f786&amp;goto=item%3Fid%3D47123631#47127844"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=CuriouslyC" class=hnuser>CuriouslyC</a> <span class=age title="2026-02-23T19:56:16 1771876576"><a href="https://news.ycombinator.com/item?id=47127844">6 hours ago</a></span> <span id=unv_47127844></span><span class=navs> | <a href=#47126391 class=clicky aria-hidden=true>root</a> | <a href=#47126875 class=clicky aria-hidden=true>parent</a> | <a href=#47126668 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47127844 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">Load is highly bursty. You can autoscale application services quickly, but scaling your database up is a slower thing.</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47127844&amp;goto=item%3Fid%3D47123631%2347127844" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47126668><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class=votelinks><center><a id=up_47126668 class=clicky href="https://news.ycombinator.com/vote?id=47126668&amp;how=up&amp;auth=1d017e5e1ed987af6940f04550efc65a272faef9&amp;goto=item%3Fid%3D47123631#47126668"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=jackfischer" class=hnuser>jackfischer</a> <span class=age title="2026-02-23T18:37:22 1771871842"><a href="https://news.ycombinator.com/item?id=47126668">8 hours ago</a></span> <span id=unv_47126668></span><span class=navs> | <a href=#47126391 class=clicky aria-hidden=true>prev</a> | <a href=#47126058 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47126668 n=6 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">Congrats guys! Curious how the read write splitting is reliable in practice due to replication lag. Do you need to run the underlying cluster with synchronous replication?</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47126668&amp;goto=item%3Fid%3D47123631%2347126668" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47128905><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47128905 class=clicky href="https://news.ycombinator.com/vote?id=47128905&amp;how=up&amp;auth=97e1bddfd8af5b0b6a62820647e93b362b773e46&amp;goto=item%3Fid%3D47123631#47128905"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=maherbeg" class=hnuser>maherbeg</a> <span class=age title="2026-02-23T21:11:20 1771881080"><a href="https://news.ycombinator.com/item?id=47128905">5 hours ago</a></span> <span id=unv_47128905></span><span class=navs> | <a href=#47126668 class=clicky aria-hidden=true>parent</a> | <a href=#47126733 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47128905 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">The way we solved it is by checking the lsn on the primary, and then waiting for the replica to catch up to that lsn before doing reads on the replica in various scenarios.</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47128905&amp;goto=item%3Fid%3D47123631%2347128905" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47126733><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47126733 class=clicky href="https://news.ycombinator.com/vote?id=47126733&amp;how=up&amp;auth=a6969632a078be231ea878b0c5fce4d1e1499765&amp;goto=item%3Fid%3D47123631#47126733"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-23T18:41:49 1771872109"><a href="https://news.ycombinator.com/item?id=47126733">7 hours ago</a></span> <span id=unv_47126733></span><span class=navs> | <a href=#47126668 class=clicky aria-hidden=true>parent</a> | <a href=#47128905 class=clicky aria-hidden=true>prev</a> | <a href=#47126058 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47126733 n=4 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">Not really, replication lag is generally an accepted trade-off. Sync replication is rarely worth it, since you take a 30% performance hit on commits and add more single points of failure.<p>We will add some replication lag-based routing soon. It will prioritize replicas with the lowest lag to maximize the chance of the query succeeding and remove replicas from the load balancer entirely if they have fallen far behind. Incidentally, removing query load helps them catch up, so this could be used as a "self-healing" mechanism.</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47126733&amp;goto=item%3Fid%3D47123631%2347126733" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47127296><td><table border=0><tbody><tr><td class=ind indent=2><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=80><td valign=top class=votelinks><center><a id=up_47127296 class=clicky href="https://news.ycombinator.com/vote?id=47127296&amp;how=up&amp;auth=b6dc88aa878faecb0bea3b1a20d97b22b1fc8fac&amp;goto=item%3Fid%3D47123631#47127296"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=jackfischer" class=hnuser>jackfischer</a> <span class=age title="2026-02-23T19:17:01 1771874221"><a href="https://news.ycombinator.com/item?id=47127296">7 hours ago</a></span> <span id=unv_47127296></span><span class=navs> | <a href=#47126668 class=clicky aria-hidden=true>root</a> | <a href=#47126733 class=clicky aria-hidden=true>parent</a> | <a href=#47126058 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47127296 n=3 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">It sounds like this is one of the few places that might be a leaky abstraction in that queries _might_ fail and the failure might effectively be silent?</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47127296&amp;goto=item%3Fid%3D47123631%2347127296" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47127464><td><table border=0><tbody><tr><td class=ind indent=3><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=120><td valign=top class=votelinks><center><a id=up_47127464 class=clicky href="https://news.ycombinator.com/vote?id=47127464&amp;how=up&amp;auth=4a41d965c35184d68709d515bf7d41e3ef8fa4bb&amp;goto=item%3Fid%3D47123631#47127464"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-23T19:27:20 1771874840"><a href="https://news.ycombinator.com/item?id=47127464">7 hours ago</a></span> <span id=unv_47127464></span><span class=navs> | <a href=#47126668 class=clicky aria-hidden=true>root</a> | <a href=#47127296 class=clicky aria-hidden=true>parent</a> | <a href=#47126058 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47127464 n=2 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">It can be silent, but usually it's loud and confusing because people do something like this (Rails example):<p><pre><code> user = User.create(email: "test@test.com")
SendWelcomeEmail.perform_later(user.id)
</code></pre>
And the job code fetches the row like so:<p><pre><code> user = User.find(id)
</code></pre>
This blows up because `find` throws an error if the record isn't there. Job queues typically use replicas for reads. This is a common gotcha: code that runs async expects the data to be there after creation.<p>There can be others, of course, especially in fintech where you have an atomic ledger, but people are usually pretty conscious about this and send those type of queries to the primary.<p>In general though, I completely agree, this is leaky and an unsolved problem. You can have performance or accuracy, but not both, and most solutions skew towards performance and make applications handle the lack of accuracy.</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47127464&amp;goto=item%3Fid%3D47123631%2347127464" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47127561><td><table border=0><tbody><tr><td class=ind indent=4><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=160><td valign=top class=votelinks><center><a id=up_47127561 class=clicky href="https://news.ycombinator.com/vote?id=47127561&amp;how=up&amp;auth=8696ed816d5237e5bceca3f656c8c64f3b7d7ab3&amp;goto=item%3Fid%3D47123631#47127561"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=jackfischer" class=hnuser>jackfischer</a> <span class=age title="2026-02-23T19:34:32 1771875272"><a href="https://news.ycombinator.com/item?id=47127561">7 hours ago</a></span> <span id=unv_47127561></span><span class=navs> | <a href=#47126668 class=clicky aria-hidden=true>root</a> | <a href=#47127464 class=clicky aria-hidden=true>parent</a> | <a href=#47126058 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47127561 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c5A">Makes sense, appreciate it</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47127561&amp;goto=item%3Fid%3D47123631%2347127561" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47126058><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class=votelinks><center><a id=up_47126058 class=clicky href="https://news.ycombinator.com/vote?id=47126058&amp;how=up&amp;auth=ad368dc7e11eeb02f36427034195a77ced610f91&amp;goto=item%3Fid%3D47123631#47126058"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=octoclaw" class=hnuser><font color=#3c963c>octoclaw</font></a> <span class=age title="2026-02-23T18:01:40 1771869700"><a href="https://news.ycombinator.com/item?id=47126058">8 hours ago</a></span> <span id=unv_47126058></span><span class=navs> | <a href=#47126668 class=clicky aria-hidden=true>prev</a> | <a href=#47128649 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47126058 n=2 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">The cross-shard aggregate rewriting is really nice. Transparently injecting count() for average calculations sounds straightforward but there are so many edge cases once you add GROUP BY, HAVING, subqueries, etc.<p>Curious about latency overhead for the common case. On a direct-to-shard read where no rewriting happens, what's the added latency from going through PgDog vs connecting to Postgres directly? Sub-millisecond?</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47126058&amp;goto=item%3Fid%3D47123631%2347126058" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47126217><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47126217 class=clicky href="https://news.ycombinator.com/vote?id=47126217&amp;how=up&amp;auth=c20c9dbbc258dd6ae0ac14d181d576a8422b4bcf&amp;goto=item%3Fid%3D47123631#47126217"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-23T18:09:35 1771870175"><a href="https://news.ycombinator.com/item?id=47126217">8 hours ago</a></span> <span id=unv_47126217></span><span class=navs> | <a href=#47126058 class=clicky aria-hidden=true>parent</a> | <a href=#47128649 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47126217 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">Subms typically, yeah. We measured the average latency between nodes in the same AZ (e.g., AWS availability zone) to be less than one ms, so you need to account for one extra hop and processing time by PgDog, which is typically fast.<p>That being said if you don't currently use a connection pooler, you will notice some latency when adding one. It's usually table stakes for Postgres at scale since you need one anyway, but it can be surprising. This especially affects "chatty" apps - the ones that send 10+ queries to service one API request, and makes bugs like N+1s considerably worse.<p>TLDR: not a free lunch, but generally acceptable at scale.</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47126217&amp;goto=item%3Fid%3D47123631%2347126217" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47128649><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class=votelinks><center><a id=up_47128649 class=clicky href="https://news.ycombinator.com/vote?id=47128649&amp;how=up&amp;auth=8b34eb7b3d1cde3ac35e333c5bb5f7b246b86fe3&amp;goto=item%3Fid%3D47123631#47128649"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=array_loader" class=hnuser><font color=#3c963c>array_loader</font></a> <span class=age title="2026-02-23T20:54:58 1771880098"><a href="https://news.ycombinator.com/item?id=47128649">5 hours ago</a></span> <span id=unv_47128649></span><span class=navs> | <a href=#47126058 class=clicky aria-hidden=true>prev</a> | <a href=#47127155 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47128649 n=2 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">(apologies for new account - NDA applies to the specifics)<p>Nice surprise to see this here today. I was working on a deployment just last week.<p>Unfortunately for me, I found that it crashed when doing a very specific bulk load (COPY FORMAT BINARY with array columns inside a transaction). The process loads around 200MB of array columns (in the region of 10K rows) into a variety of tables. Very early in the COPY process PgDog crashes with :<p>"pgdog router error: failed to fill whole buffer"<p>So it appears something is not quite right for my specific use case (COPY with array columns). I'm not familiar enough with Rust but the failed to fill whole buffer seemed to come from Rust (rather than PgDog) based on what little I could find with searches.<p>I was very disappointed as it looked much simpler to get set up and running that PgPool-II (which I have had to revert to as my backup plan - I'm finding it more difficult to configured, but it does cope with the COPY command without issues).<p>I would have preferred to stick with PgDog.</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47128649&amp;goto=item%3Fid%3D47123631%2347128649" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47128694><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47128694 class=clicky href="https://news.ycombinator.com/vote?id=47128694&amp;how=up&amp;auth=04a8a2ea620e724b4519a9e9b38562c3243016ee&amp;goto=item%3Fid%3D47123631#47128694"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-23T20:57:29 1771880249"><a href="https://news.ycombinator.com/item?id=47128694">5 hours ago</a></span> <span id=unv_47128694></span><span class=navs> | <a href=#47128649 class=clicky aria-hidden=true>parent</a> | <a href=#47127155 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47128694 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">I think we may have fixed this 3 weeks ago: <a href=https://github.com/pgdogdev/pgdog/pull/744 rel=nofollow>https://github.com/pgdogdev/pgdog/pull/744</a><p>Might be worth another try. If not, a GitHub issue with more specifics would be great, and we'll take a look. Also, if binary encoding isn't working out, try using text - it's more compatible between Postgres versions:<p><pre><code> [general]
resharding_copy_format = "text"</code></pre></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47128694&amp;goto=item%3Fid%3D47123631%2347128694" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47126736><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class=votelinks><center><a id=up_47126736 class=clicky href="https://news.ycombinator.com/vote?id=47126736&amp;how=up&amp;auth=79c2146a13f7c389f708e22de91053b9c025f770&amp;goto=item%3Fid%3D47123631#47126736"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=I_am_tiberius" class=hnuser>I_am_tiberius</a> <span class=age title="2026-02-23T18:42:00 1771872120"><a href="https://news.ycombinator.com/item?id=47126736">7 hours ago</a></span> <span id=unv_47126736></span><span class=navs> | <a href=#47127155 class=clicky aria-hidden=true>prev</a> | <a href=#47130284 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47126736 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">I really hope to use the sharding feature one day.</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47126736&amp;goto=item%3Fid%3D47123631%2347126736" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47130284><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class=votelinks><center><a id=up_47130284 class=clicky href="https://news.ycombinator.com/vote?id=47130284&amp;how=up&amp;auth=81f95045acece4a78664db063cc5618324d28a18&amp;goto=item%3Fid%3D47123631#47130284"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=oulipo2" class=hnuser>oulipo2</a> <span class=age title="2026-02-23T23:02:18 1771887738"><a href="https://news.ycombinator.com/item?id=47130284">3 hours ago</a></span> <span id=unv_47130284></span><span class=navs> | <a href=#47126736 class=clicky aria-hidden=true>prev</a> | <a href=#47125908 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47130284 n=2 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">How do you know when/if it's justified to add additional complexity like PgDog?<p>Is there a number of simultaneous connection / req per sec that's a good threshold?<p>Is it easy on my postgres instance to get the number of simulataneous connections, for instance if I simulate traffic, to know if I would gain anything from a connection pooler?</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47130284&amp;goto=item%3Fid%3D47123631%2347130284" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47131616><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47131616 class=clicky href="https://news.ycombinator.com/vote?id=47131616&amp;how=up&amp;auth=a7b201804545a40a7f967ee0372fe5aec16093e0&amp;goto=item%3Fid%3D47123631#47131616"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=levkk" class=hnuser>levkk</a> <span class=age title="2026-02-24T01:20:15 1771896015"><a href="https://news.ycombinator.com/item?id=47131616">1 hour ago</a></span> <span id=unv_47131616></span><span class=navs> | <a href=#47130284 class=clicky aria-hidden=true>parent</a> | <a href=#47125908 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47131616 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">I would say, over 100 Postgres connections, consider getting a connection pooler. Requests per second is highly variable. Postgres can serve a lot of them, as long as you keep the number of server connections low - that's what the pooler is for.<p>You can use pgbench to benchmark this on local pretty easily. The TPS curve will be interesting. At first, the connection pooler will cause a decrease and as you add more and more clients (-c parameter), you should see increasing benefits.<p>Ultimately, you add connection poolers when you don't have any other option: you have hundreds of app containers with dozens of connections each and Postgres can't handle it anymore, so it's a necessity really.<p>Load balancing becomes useful when you start adding read replicas. Sharding is necessary when you're approaching the vertical limit of your cloud provider (on the biggest instance or close).</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47131616&amp;goto=item%3Fid%3D47123631%2347131616" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47125908><td><table border=0><tbody><tr><td class=ind indent=0><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=0><td valign=top class=votelinks><center><a id=up_47125908 class=clicky href="https://news.ycombinator.com/vote?id=47125908&amp;how=up&amp;auth=459e19c61a7d2ff3153381fc3a6d793c87c8b876&amp;goto=item%3Fid%3D47123631#47125908"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=cpursley" class=hnuser>cpursley</a> <span class=age title="2026-02-23T17:53:09 1771869189"><a href="https://news.ycombinator.com/item?id=47125908">8 hours ago</a></span> <span id=unv_47125908></span><span class=navs> | <a href=#47130284 class=clicky aria-hidden=true>prev</a> <a class="togg clicky" id=47125908 n=7 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">Looks great - I'd love to include it in <a href=https://postgresisenough.dev/ rel=nofollow>https://postgresisenough.dev</a> (just put in a PR: <a href="https://github.com/agoodway/postgresisenough?tab=readme-ov-file#add-a-tool" rel=nofollow>https://github.com/agoodway/postgresisenough?tab=readme-ov-f...</a>)</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47125908&amp;goto=item%3Fid%3D47123631%2347125908" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47127173><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47127173 class=clicky href="https://news.ycombinator.com/vote?id=47127173&amp;how=up&amp;auth=1a39f8fe44e91ad9971b27d28f565af8c268fe69&amp;goto=item%3Fid%3D47123631#47127173"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=pbreit" class=hnuser>pbreit</a> <span class=age title="2026-02-23T19:10:05 1771873805"><a href="https://news.ycombinator.com/item?id=47127173">7 hours ago</a></span> <span id=unv_47127173></span><span class=navs> | <a href=#47125908 class=clicky aria-hidden=true>parent</a> | <a href=#47126518 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47127173 n=2 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">How well does PG work with 10-20 million (financial) records per day? Basic stuff: a few writes per, some reads, generating some analytics, etc.</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47127173&amp;goto=item%3Fid%3D47123631%2347127173" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47128343><td><table border=0><tbody><tr><td class=ind indent=2><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=80><td valign=top class=votelinks><center><a id=up_47128343 class=clicky href="https://news.ycombinator.com/vote?id=47128343&amp;how=up&amp;auth=e46defabd93df7de3b800622814923040eeaf7b8&amp;goto=item%3Fid%3D47123631#47128343"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=cpursley" class=hnuser>cpursley</a> <span class=age title="2026-02-23T20:31:11 1771878671"><a href="https://news.ycombinator.com/item?id=47128343">6 hours ago</a></span> <span id=unv_47128343></span><span class=navs> | <a href=#47125908 class=clicky aria-hidden=true>root</a> | <a href=#47127173 class=clicky aria-hidden=true>parent</a> | <a href=#47126518 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47128343 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c5A">The entire point of just using Postgres went right over your head…</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47128343&amp;goto=item%3Fid%3D47123631%2347128343" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47126518><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47126518 class=clicky href="https://news.ycombinator.com/vote?id=47126518&amp;how=up&amp;auth=35f5fdd229c1e4a66109d6f3e2a713cb18f18d9e&amp;goto=item%3Fid%3D47123631#47126518"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=nebezb" class=hnuser>nebezb</a> <span class=age title="2026-02-23T18:26:53 1771871213"><a href="https://news.ycombinator.com/item?id=47126518">8 hours ago</a></span> <span id=unv_47126518></span><span class=navs> | <a href=#47125908 class=clicky aria-hidden=true>parent</a> | <a href=#47127173 class=clicky aria-hidden=true>prev</a> | <a href=#47126452 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47126518 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">While the lift to add to your database is low, I dont think youre at a point you can outsource the work.<p>But all the better if they do!</p></div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47126518&amp;goto=item%3Fid%3D47123631%2347126518" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47126452><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47126452 class=clicky href="https://news.ycombinator.com/vote?id=47126452&amp;how=up&amp;auth=83bf665d81054051be3d8c654618aebb8b318fbb&amp;goto=item%3Fid%3D47123631#47126452"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=aram99" class=hnuser>aram99</a> <span class=age title="2026-02-23T18:22:52 1771870972"><a href="https://news.ycombinator.com/item?id=47126452">8 hours ago</a></span> <span id=unv_47126452></span><span class=navs> | <a href=#47125908 class=clicky aria-hidden=true>parent</a> | <a href=#47126518 class=clicky aria-hidden=true>prev</a> | <a href=#47126357 class=clicky aria-hidden=true>next</a> <a class="togg clicky" id=47126452 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">.</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47126452&amp;goto=item%3Fid%3D47123631%2347126452" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47126357><td><table border=0><tbody><tr><td class=ind indent=1><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=40><td valign=top class=votelinks><center><a id=up_47126357 class=clicky href="https://news.ycombinator.com/vote?id=47126357&amp;how=up&amp;auth=d0e3ee369540f6e19bea290d4aa868e8c32ddbc6&amp;goto=item%3Fid%3D47123631#47126357"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=verdverm" class=hnuser>verdverm</a> <span class=age title="2026-02-23T18:17:51 1771870671"><a href="https://news.ycombinator.com/item?id=47126357">8 hours ago</a></span> <span id=unv_47126357></span><span class=navs> | <a href=#47125908 class=clicky aria-hidden=true>parent</a> | <a href=#47126452 class=clicky aria-hidden=true>prev</a> <a class="togg clicky" id=47126357 n=2 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c5A">Why don't you just do it yourself if you maintain a curated resource list?</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47126357&amp;goto=item%3Fid%3D47123631%2347126357" rel=nofollow>reply</a></u></font></p></div></div></table><tr class="athing comtr" id=47126800><td><table border=0><tbody><tr><td class=ind indent=2><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=1 width=80><td valign=top class=votelinks><center><a id=up_47126800 class=clicky href="https://news.ycombinator.com/vote?id=47126800&amp;how=up&amp;auth=64c2eaf13c9edb38696fd3d301195aade7b49bb7&amp;goto=item%3Fid%3D47123631#47126800"><div class=votearrow title=upvote></div></a></center><td class=default><div style=margin-top:2px;margin-bottom:-10px><span class=comhead><a href="https://news.ycombinator.com/user?id=cpursley" class=hnuser>cpursley</a> <span class=age title="2026-02-23T18:45:26 1771872326"><a href="https://news.ycombinator.com/item?id=47126800">7 hours ago</a></span> <span id=unv_47126800></span><span class=navs> | <a href=#47125908 class=clicky aria-hidden=true>root</a> | <a href=#47126357 class=clicky aria-hidden=true>parent</a> <a class="togg clicky" id=47126800 n=1 href=javascript:void(0)>[]</a><span class=onstory></span></span></span></div><br>
<div class=comment><div class="commtext c00">Wanted to give them chance to write it up as they like</div><div class=reply><p><font size=1><u><a href="https://news.ycombinator.com/reply?id=47126800&amp;goto=item%3Fid%3D47123631%2347126800" rel=nofollow>reply</a></u></font></p></div></div></table></table><br><br>
<tr><td><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" height=10 width=0><table width=100% cellspacing=0 cellpadding=1><tbody><tr><td bgcolor=#ff6600></table><br>
<center><span class=yclinks><a href=https://news.ycombinator.com/newsguidelines.html>Guidelines</a> | <a href=https://news.ycombinator.com/newsfaq.html>FAQ</a> | <a href=https://news.ycombinator.com/lists>Lists</a> | <a href=https://github.com/HackerNews/API>API</a> | <a href=https://news.ycombinator.com/security.html>Security</a> | <a href=https://www.ycombinator.com/legal/>Legal</a> | <a href=https://www.ycombinator.com/apply/>Apply to YC</a> | <a href=mailto:hn@ycombinator.com>Contact</a></span><br><br>
<form action=//hn.algolia.com/>Search: <input type=text name=q size=17 autocorrect=off spellcheck=false autocapitalize=off autocomplete=off value><template shadowrootmode=user-agent><div contenteditable=plaintext-only></div></template></form></center></table></center><single-file-infobar style="accent-color: initial !important; place-content: initial !important; place-items: initial !important; place-self: initial !important; alignment-baseline: initial !important; anchor-name: initial !important; anchor-scope: initial !important; animation-composition: initial !important; animation: initial !important; appearance: initial !important; aspect-ratio: initial !important; backdrop-filter: initial !important; backface-visibility: initial !important; background: initial !important; background-blend-mode: initial !important; baseline-shift: initial !important; block-size: initial !important; border-block: initial !important; border: initial !important; border-radius: initial !important; border-collapse: initial !important; border-end-end-radius: initial !important; border-end-start-radius: initial !important; border-inline: initial !important; border-start-end-radius: initial !important; border-start-start-radius: initial !important; inset: initial !important; box-shadow: initial !important; box-sizing: initial !important; break-after: initial !important; break-before: initial !important; break-inside: initial !important; buffered-rendering: initial !important; caption-side: initial !important; caret-color: initial !important; clear: initial !important; clip: initial !important; clip-path: initial !important; clip-rule: initial !important; color: initial !important; color-interpolation: initial !important; color-interpolation-filters: initial !important; color-scheme: initial !important; column-count: initial !important; column-fill: initial !important; gap: initial !important; column-rule-color: initial !important; column-rule-style: initial !important; column-rule-width: initial !important; column-span: initial !important; column-width: initial !important; contain: initial !important; contain-intrinsic-block-size: initial !important; contain-intrinsic-size: initial !important; contain-intrinsic-inline-size: initial !important; container-name: initial !important; container-type: initial !important; content: initial !important; content-visibility: initial !important; counter-increment: initial !important; counter-reset: initial !important; counter-set: initial !important; cursor: initial !important; cx: initial !important; cy: initial !important; direction: initial !important; display: initial !important; dominant-baseline: initial !important; dynamic-range-limit: initial !important; empty-cells: initial !important; field-sizing: initial !important; fill: initial !important; fill-opacity: initial !important; fill-rule: initial !important; filter: initial !important; flex: initial !important; flex-flow: initial !important; float: initial !important; flood-color: initial !important; flood-opacity: initial !important; font-family: initial !important; font-feature-settings: initial !important; font-kerning: initial !important; font-optical-sizing: initial !important; font-palette: initial !important; font-size: initial !important; font-size-adjust: initial !important; font-style: initial !important; font-synthesis-small-caps: initial !important; font-synthesis-style: initial !important; font-synthesis-weight: initial !important; font-variant-alternates: initial !important; font-variant-caps: initial !important; font-variant-east-asian: initial !important; font-variant-ligatures: initial !important; font-variant-numeric: initial !important; font-variant-position: initial !important; font-variation-settings: initial !important; font-weight: initial !important; font-width: initial !important; glyph-orientation-horizontal: initial !important; glyph-orientation-vertical: initial !important; grid: initial !important; grid-column-end: initial !important; grid-column-start: initial !important; grid-row-end: initial !important; grid-row-start: initial !important; hanging-punctuation: initial !important; height: initial !important; hyphenate-character: initial !important; hyphens: initial !important; image-orientation: initial !important; image-rendering: initial !important; inline-size: initial !important; inset-block: initial !important; inset-inline: initial !important; isolation: initial !important; letter-spacing: initial !important; lighting-color: initial !important; line-break: initial !important; line-height: initial !important; list-style: initial !important; margin-block: initial !important; margin: initial !important; margin-inline: initial !important; margin-trim: initial !important; marker: initial !important; mask: initial !important; mask-composite: initial !important; mask-mode: initial !important; mask-size: initial !important; mask-type: initial !important; math-shift: initial !important; math-style: initial !important; max-block-size: initial !important; max-height: initial !important; max-inline-size: initial !important; max-width: initial !important; min-block-size: initial !important; min-height: initial !important; min-inline-size: initial !important; min-width: initial !important; mix-blend-mode: initial !important; object-fit: initial !important; object-position: initial !important; offset-anchor: initial !important; offset-distance: initial !important; offset-path: initial !important; offset-position: initial !important; offset-rotate: initial !important; opacity: initial !important; order: initial !important; orphans: initial !important; outline: initial !important; outline-offset: initial !important; overflow-block: initial !important; overflow-inline: initial !important; overflow-wrap: initial !important; overflow: initial !important; overscroll-behavior-block: initial !important; overscroll-behavior-inline: initial !important; overscroll-behavior: initial !important; padding-block: initial !important; padding: initial !important; padding-inline: initial !important; paint-order: initial !important; perspective: initial !important; perspective-origin: initial !important; pointer-events: initial !important; position: initial !important; position-anchor: initial !important; position-area: initial !important; position-try: initial !important; position-visibility: initial !important; print-color-adjust: initial !important; quotes: initial !important; r: initial !important; resize: initial !important; rotate: initial !important; ruby-align: initial !important; ruby-overhang: initial !important; ruby-position: initial !important; rx: initial !important; ry: initial !important; scale: initial !important; scroll-behavior: initial !important; scroll-margin-block: initial !important; scroll-margin: initial !important; scroll-margin-inline: initial !important; scroll-padding-block: initial !important; scroll-padding: initial !important; scroll-padding-inline: initial !important; scroll-snap-align: initial !important; scroll-snap-stop: initial !important; scroll-snap-type: initial !important; scroll-timeline: initial !important; scrollbar-color: initial !important; scrollbar-gutter: initial !important; scrollbar-width: initial !important; shape-image-threshold: initial !important; shape-margin: initial !important; shape-outside: initial !important; shape-rendering: initial !important; speak-as: initial !important; stop-color: initial !important; stop-opacity: initial !important; stroke: initial !important; stroke-color: initial !important; stroke-dasharray: initial !important; stroke-dashoffset: initial !important; stroke-linecap: initial !important; stroke-linejoin: initial !important; stroke-miterlimit: initial !important; stroke-opacity: initial !important; stroke-width: initial !important; tab-size: initial !important; table-layout: initial !important; text-align: initial !important; text-align-last: initial !important; text-anchor: initial !important; text-autospace: initial !important; text-box: initial !important; text-combine-upright: initial !important; text-decoration: initial !important; text-decoration-skip-ink: initial !important; text-emphasis-color: initial !important; text-emphasis-position: initial !important; text-emphasis-style: initial !important; text-indent: initial !important; text-orientation: initial !important; text-overflow: initial !important; text-rendering: initial !important; text-shadow: initial !important; text-transform: initial !important; text-underline-offset: initial !important; text-underline-position: initial !important; text-wrap: initial !important; timeline-scope: initial !important; touch-action: initial !important; transform: initial !important; transform-box: initial !important; transform-origin: initial !important; transform-style: initial !important; transition: initial !important; translate: initial !important; unicode-bidi: initial !important; vector-effect: initial !important; vertical-align: initial !important; view-timeline: initial !important; view-transition-class: initial !important; view-transition-name: initial !important; visibility: initial !important; white-space: initial !important; widows: initial !important; width: initial !important; will-change: initial !important; word-break: initial !important; word-spacing: initial !important; writing-mode: initial !important; x: initial !important; y: initial !important; z-index: initial !important; zoom: initial !important; -apple-pay-button-style: initial !important; -apple-pay-button-type: initial !important; border-spacing: initial !important; -webkit-box-align: initial !important; -webkit-box-decoration-break: initial !important; -webkit-box-direction: initial !important; -webkit-box-flex: initial !important; -webkit-box-flex-group: initial !important; -webkit-box-lines: initial !important; -webkit-box-ordinal-group: initial !important; -webkit-box-orient: initial !important; -webkit-box-pack: initial !important; -webkit-box-reflect: initial !important; -webkit-column-axis: initial !important; -webkit-column-progression: initial !important; -webkit-cursor-visibility: initial !important; -webkit-font-smoothing: initial !important; -webkit-hyphenate-limit-after: initial !important; -webkit-hyphenate-limit-before: initial !important; -webkit-hyphenate-limit-lines: initial !important; -webkit-initial-letter: initial !important; -webkit-line-align: initial !important; -webkit-line-box-contain: initial !important; -webkit-line-clamp: initial !important; -webkit-line-grid: initial !important; -webkit-line-snap: initial !important; -webkit-locale: initial !important; -webkit-nbsp-mode: initial !important; -webkit-rtl-ordering: initial !important; -webkit-text-fill-color: initial !important; -webkit-text-security: initial !important; -webkit-text-stroke-color: initial !important; -webkit-text-stroke-width: initial !important; -webkit-text-zoom: initial !important; -webkit-user-drag: initial !important; -webkit-user-modify: initial !important; -webkit-user-select: initial !important;"><template shadowrootmode=open><div><style>.infobar,.infobar .infobar-icon,.infobar .infobar-link-icon {min-inline-size:28px;min-block-size:28px;box-sizing:border-box;}.infobar,.infobar .infobar-close-icon,.infobar .infobar-link-icon {opacity:0.7;transition:opacity 250ms;}.infobar:hover,.infobar .infobar-close-icon:hover,.infobar .infobar-link-icon:hover {opacity:1;}.infobar,.infobar-content {display:flex;}.infobar {position:fixed;max-height:calc(100% - 32px);top:16px;right:16px;margin-inline-start:16px;margin-block-end:16px;color:#2d2d2d;background-color:#737373;border:2px solid;border-color:#eee;border-radius:16px;z-index:2147483647;animation-name:flash;animation-duration:.5s;animation-timing-function:cubic-bezier(0.39,0.58,0.57,1);animation-delay:1s;animation-iteration-count:2;}.infobar:valid,.infobar:not(:focus-within):not(.infobar-focus) .infobar-content {display:none;}.infobar:focus-within,.infobar.infobar-focus {background-color:#f9f9f9;border-color:#878787;border-radius:8px;opacity:1;transition-property:opacity,background-color,border-color,border-radius,color;}.infobar-content {border:2px solid;border-color:#f9f9f9;border-radius:6px;background-color:#f9f9f9;overflow:auto;}.infobar-content span {font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:18px;word-break:break-word;white-space:pre-wrap;margin-inline:4px;margin-block:4px;}.infobar .infobar-icon,.infobar .infobar-close-icon,.infobar .infobar-link-icon {cursor:pointer;background-position:center;background-repeat:no-repeat;}.infobar .infobar-close-icon,.infobar .infobar-link-icon {align-self:flex-start;}.infobar .infobar-icon {position:absolute;min-inline-size:24px;min-block-size:24px;}@keyframes flash {0%,100% { background-color:#737373;}50% { background-color:#dd6a00;}}.infobar:focus-within .infobar-icon,.infobar.infobar-focus .infobar-icon {z-index:-1;background-image:none;margin:4px;}.infobar .infobar-close-icon {min-inline-size:22px;min-block-size:22px;}.infobar .infobar-icon {background-color:transparent;background-size:70%;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABABAMAAABYR2ztAAABhmlDQ1BJQ0MgcHJvZmlsZQAAKJF9kj1Iw0AYht+mSkUrDnYQcchQnSyIijqWKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjx4LiH9+59+e67A4RGhalm1wSgapaRisfEbG5VDLyiDwEAvZiVmKkn0osZeI6ve/j4ehfhWd7n/hz9St5kgE8kjjLdsIg3iGc2LZ3zPnGIlSSF+Jx43KACiR+5Lrv8xrnosMAzQ0YmNU8cIhaLHSx3MCsZKvE0cVhRNcoXsi4rnLc4q5Uaa9XJbxjMaytprtMcQRxLSCAJETJqKKMCCxFaNVJMpGg/5uEfdvxJcsnkKoORYwFVqJAcP/gb/O6tWZiadJOCMaD7xbY/RoHALtCs2/b3sW03TwD/M3Cltf3VBjD3SXq9rYWPgIFt4OK6rcl7wOUOMPSkS4bkSH6aQqEAvJ/RM+WAwVv6EGtu31r7OH0AMtSr5Rvg4BAYK1L2use9ezr79u+ZVv9+AFlNcp0UUpiqAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH5AsHADIRLMaOHwAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAPUExURQAAAIqKioyNjY2OjvDw8L2y1DEAAAABdFJOUwBA5thmAAAAAWJLR0QB/wIt3gAAAGNJREFUSMdjYCAJsLi4OBCQx6/CBQwIGIDPCBcXAkYQUsACU+AwlBVQHg6Eg5pgZBGOboIJZugDFwRwoJECJCUOhJI1wZwzqmBUwagCuipgIqTABG9h7YIKaKGAURAFEF/6AQAO4HqSoDP8bgAAAABJRU5ErkJggg==);}.infobar .infobar-link-icon {right:4px;background-size:60%;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAgMAAADXB5lNAAABhmlDQ1BJQ0MgcHJvZmlsZQAAKJF9kj1Iw0AYht+mSkUrDnYQcchQnSyIijqWKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjx4LiH9+59+e67A4RGhalm1wSgapaRisfEbG5VDLyiDwEAvZiVmKkn0osZeI6ve/j4ehfhWd7n/hz9St5kgE8kjjLdsIg3iGc2LZ3zPnGIlSSF+Jx43KACiR+5Lrv8xrnosMAzQ0YmNU8cIhaLHSx3MCsZKvE0cVhRNcoXsi4rnLc4q5Uaa9XJbxjMaytprtMcQRxLSCAJETJqKKMCCxFaNVJMpGg/5uEfdvxJcsnkKoORYwFVqJAcP/gb/O6tWZiadJOCMaD7xbY/RoHALtCs2/b3sW03TwD/M3Cltf3VBjD3SXq9rYWPgIFt4OK6rcl7wOUOMPSkS4bkSH6aQqEAvJ/RM+WAwVv6EGtu31r7OH0AMtSr5Rvg4BAYK1L2use9ezr79u+ZVv9+AFlNcp0UUpiqAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH5AsHAB8H+DhhoQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAJUExURQAAAICHi4qKioTuJAkAAAABdFJOUwBA5thmAAAAAWJLR0QCZgt8ZAAAAJJJREFUOI3t070NRCEMA2CnYAOyDyPwpHj/Va7hJ3FzV7zy3ET5JIwoAF6Jk4wzAJAkzxAYG9YRTgB+24wBgKmfrGAKTcEfAY4KRlRoIeBTgKOCERVaCPgU4Khge2GqKOBTgKOCERVaAEC/4PNcnyoSWHpjqkhwKxbcig0Q6AorXYF/+A6eIYD1lVbwG/jdA6/kA2THRAURVubcAAAAAElFTkSuQmCC);}.infobar .infobar-close-icon {appearance:none;background-size:80%;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAgMAAADXB5lNAAABhmlDQ1BJQ0MgcHJvZmlsZQAAKJF9kj1Iw0AYht+mSkUrDnYQcchQnSyIijqWKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjx4LiH9+59+e67A4RGhalm1wSgapaRisfEbG5VDLyiDwEAvZiVmKkn0osZeI6ve/j4ehfhWd7n/hz9St5kgE8kjjLdsIg3iGc2LZ3zPnGIlSSF+Jx43KACiR+5Lrv8xrnosMAzQ0YmNU8cIhaLHSx3MCsZKvE0cVhRNcoXsi4rnLc4q5Uaa9XJbxjMaytprtMcQRxLSCAJETJqKKMCCxFaNVJMpGg/5uEfdvxJcsnkKoORYwFVqJAcP/gb/O6tWZiadJOCMaD7xbY/RoHALtCs2/b3sW03TwD/M3Cltf3VBjD3SXq9rYWPgIFt4OK6rcl7wOUOMPSkS4bkSH6aQqEAvJ/RM+WAwVv6EGtu31r7OH0AMtSr5Rvg4BAYK1L2use9ezr79u+ZVv9+AFlNcp0UUpiqAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH5AsHAB8VC4EQ6QAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAJUExURQAAAICHi4qKioTuJAkAAAABdFJOUwBA5thmAAAAAWJLR0QCZgt8ZAAAAJtJREFUOI3NkrsBgCAMRLFwBPdxBArcfxXFkO8rbKWAAJfHJ9faf9vuYX/749T5NmShm3bEwbe2SxeuM4+2oxDL1cDoKtVUjRy+tH78Cv2CS+wIiQNC1AEhk4AQeUTMWUJMfUJMSEJMSEY8kIx4IONroaYAimNxsXp1PA7PxwfVL8QnowwoVC0lig07wDDVUjAdbAnjwtow/z/bDW7eI4M2KruJAAAAAElFTkSuQmCC);}.infobar { top:16px; bottom:auto; }.infobar { right:16px; left:auto; }</style><form class="infobar"><span tabindex="-1" class="infobar-icon"></span><span tabindex="-1" class="infobar-content"><input type="checkbox" required="" class="infobar-close-icon" title="Close"><span>Tue Feb 24 2026 10:40:40 GMT+0800 (中国标准时间)</span><a class="infobar-link-icon" target="_blank" rel="noopener noreferrer" title="Open source URL: https://news.ycombinator.com/item?id=47123631" href="https://news.ycombinator.com/item?id=47123631"></a></span></form><script>function Wo(n,{saveUrl:e,infobarContent:t,saveDate:a}){if(e){const o=n.querySelector("single-file-infobar").shadowRoot;o.querySelector(".infobar-content span").textContent=t||a;const i=o.querySelector(".infobar-content .infobar-link-icon");i.href=e,i.title="Open source URL: "+e}};function Ho(n,e=_o){const t=n.evaluate("//comment()",n,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null);let a=t&&t.singleNodeValue;if(a&&a.nodeType==Node.COMMENT_NODE&&a.textContent.includes(e)){const n=a.textContent.split("\n"),[,,e,...t]=n,o=e.match(/^ url: (.*) ?$/),i=o&&o[1];if(i){let n,e;if(t.length&&(e=t[0].split("saved date: ")[1],e&&t.shift(),t.length>1)){let e=t[0].split("info: ")[1].trim();for(let n=1;n<t.length-1;n++)e+="\n"+t[n].trim();n=e.trim()}return{saveUrl:i,infobarContent:n,saveDate:e}}}};(function Go(n,e){const t=Ho(n,e);t&&t.saveUrl&&Wo(n,t)})(document, "SingleFile");</script></div></template></single-file-infobar>