8 comments

  • cataflutter4 hours ago
    Decent article, but some remarks:<p>1) It seems these two statements conflict with each other:<p>&gt; The oldest such transaction sets the cutoff—referred to as the &quot;MVCC horizon.&quot; Until that transaction completes, every dead tuple <i>newer than its snapshot</i> is retained.<p>and<p>&gt; For example, imagine three analytics queries, each running for 40 seconds, staggered 20 seconds apart. No individual query would trigger a timeout for running too long. But because one is always active, the horizon never advances, and the effect on vacuum is the same as one transaction that never ends.<p>If the three analytics *transactions* (it&#x27;s transactions that matter, not queries, although there is some subtlety around deferred transactions not acquiring a snapshot until the first query) are started at different times, they will have staggered snapshots and so once the first completes, this should allow the vacuum to advance.<p>2) Although the problem about this query:<p><pre><code> SELECT * FROM jobs WHERE status = &#x27;pending&#x27; ORDER BY run_at LIMIT 1 FOR UPDATE SKIP LOCKED; </code></pre> having to consider dead tuples is a genuine concern and performance problem, this can also be mitigated by adding a monotonically increasing column and adding a `WHERE column &lt; ?` clause, provided you have also added an index to make that pagination efficient. This way you don&#x27;t need to consider dead tuples and they &#x27;only&#x27; waste space whilst waiting to be vacuumed, rather than also bogging down read perf.<p>There is a little subtlety around how you guarantee that the column is monotonically increasing, given concurrent writers, but the answer to that depends on what tricks you can fit into your application.<p>3) I almost want to say that the one-line summary is &#x27;Don&#x27;t combine (very) long-running transactions with (very) high transaction rates in Postgres&#x27;<p>(Is this a fair representation?)
    • nine_k3 hours ago
      For (2): the problem is that the index would still need to keep the dead tuples, until Postgres is positively certain that no transaction holds them, and runs vacuum over them. It may speed up things a bit, but would still overflow the disk storage eventually. It may still prevent other tables from being vacuumed, too!
      • cataflutter2 hours ago
        For disk usage, yes this doesn&#x27;t address anything.<p>But for read performance (which is IMO what the section in the article was motivated by), it doesn&#x27;t actually matter to have a bunch of entries corresponding to dead tuples in your index, provided Postgres doesn&#x27;t need to actually consider the dead tuples as part of your query.<p>So if you have a monotonically increasing `job_id` and that&#x27;s indexed, then so long as you process your jobs in increasing `job_id` order, you can use the index and guarantee you don&#x27;t have to keep reconsidering the dead tuples corresponding to jobs that already completed (if that makes sense).<p>[This is because the index is a b-tree, which supports efficient (O(log n) page reads for n entries) seeking on (any prefix of) the columns in the index.]
        • nine_k1 hour ago
          This is fair! This should as you descripbe work with a partial index, and with picking the lowest ID that has status = pending (via that index) which is not locked (via select ... for update skip locked). The query plan should be triple-checked though to actually use the index.
  • nine_k3 hours ago
    In short:<p>* Postgres still has the same problem with vacuum horizon, when a long-running query can block vacuuming of a quick-churning table. (The author uses a benchmark from 2015 when the problem was already well-understood.)<p>* Stock Postgres still has no tools good enough against it.<p>* The author&#x27;s company special version of Postgres does have such tools; a few polite promotions of it are strewn across the article.<p>My conclusion: it&#x27;s still not wise to mix long (OLAP-style) loads and quick-churning (queue-style) loads on the same Postgres instance. Maybe running 0MQ or even RMQ may be an easier solution, depending on the requirements to the queue.
  • simeonGriggs5 hours ago
    Yo! Author here, I’ll be around if anyone’s got questions!
    • dondraper363 hours ago
      If I understood correctly, the queue implementation in the blog post holds a transaction while an operation is in progress.<p>I see the advice to make it as short as possible, but why can’t we update the status column to, say, “processing” and avoid potentially long transactions at all?
      • oxidant43 minutes ago
        This works well for jobs that are long-ish. You need another process to sweep for orphaned jobs and requeue or fail them. Add a timestamp of when it got picked up to keep track
    • jeeybee4 hours ago
      Did you test with fillfactor &lt; 100 on the queue table? With HOT updates, status changes can reuse dead space without creating new index entries, which seems like it could significantly delay the onset of the death spiral?
      • mattashii4 hours ago
        If the status column changes, and an index depends on the contents of that status column (be it by referencing it in its columns, or in the index&#x27;s WHERE filter) then an update of the status column will prevent the HOT optimization from being applied.
      • EffCompute4 hours ago
        [dead]
  • sp19821 hour ago
    The problem is way worse if you update rows, if you stick with insert and delete you can get quite far.
  • sebmellen4 hours ago
    Postgres can do so much. I see people choose Kafka and SQS for things that Graphile Worker could do all day long.
    • mikeocool4 hours ago
      “Use Postgres for everything” is a great philosophy at low&#x2F;medium scale to keep things simple, but there comes a scaling point where I want my SQL database doing as little possible.<p>It’s basically always the bottleneck&#x2F;problem source in a lot of systems.
      • jghn3 hours ago
        Of course. The flip side is that many, many more people are in the &quot;low&#x2F;medium scale&quot; zone than would self report. Everyone thinks they&#x27;re a scale outlier because people tend to think in relative terms based on their experience. Just because something is larger scale than one is used to, doesn&#x27;t mean it&#x27;s high scale.
      • tibbar4 hours ago
        Yes. For example you&#x27;ll typically have a &quot;budget&quot; of 1-10k writes&#x2F;sec. And a single heavy join can essentially take you offline. Even relatively modest enterprises typically need to shift some query patterns to OLAP&#x2F;nosql&#x2F;redis&#x2F;etc. before very long.
    • zer00eyz4 hours ago
      &gt; I see people choose Kafka and SQS<p>SQS is dead simple, and if your in AWS (forever) it is &quot;in the stack&quot; with some easy to use features that may make sense to you (delay queue is a great one).<p>Kafka is... a lot. If you need what it provides, then it&#x27;s great. You just have to be able to support it, and thats non trivial.<p>I can point to more than a hand full of Kafka project that exist because it was clear that someone wanted it on their resume. I dont think any one is doing that with SQS, it is just (a fairly good utility). However if you want to leave (or branch out from) AWS and you&#x27;re reliant on it, good luck.
  • richwater5 hours ago
    It would be nice if this ad at least explained a little bit of the technical side of the solution.
    • simeonGriggs3 hours ago
      We’ve got a separate blog post all about how traffic control works: <a href="https:&#x2F;&#x2F;planetscale.com&#x2F;blog&#x2F;behind-the-scenes-how-traffic-control-works" rel="nofollow">https:&#x2F;&#x2F;planetscale.com&#x2F;blog&#x2F;behind-the-scenes-how-traffic-c...</a>
    • sgarland5 hours ago
      It sounds vaguely like InnoDB’s concurrency control solution which uses tokens [0] as a unit of maximum work a query can perform.<p>0: <a href="https:&#x2F;&#x2F;dev.mysql.com&#x2F;doc&#x2F;refman&#x2F;8.4&#x2F;en&#x2F;innodb-performance-thread_concurrency.html" rel="nofollow">https:&#x2F;&#x2F;dev.mysql.com&#x2F;doc&#x2F;refman&#x2F;8.4&#x2F;en&#x2F;innodb-performance-t...</a>
      • sroussey7 minutes ago
        tickets, not tokens, but yeah
  • Serhii-Set3 hours ago
    [dead]
  • johnwhitman2 hours ago
    [dead]