In case anyone’s an SQL Server user and you have a regular app query suddenly timing out every so often on a large table which otherwise takes 10ms, you’ll probably be experiencing the statistic updates penalty.<p>When MSSQL decides it wants to recheck statistics for a regularly performed query, it picks the Nth “lucky” execution of your otherwise fast query to instead now update table
/index statistics.<p>To observers, this query is suddenly super slow and may even time out. Very confusing.<p>A workaround is to enable “async statistics update”, this won’t reoccur.
We have been bitten by the same behavior. I gave a talk with a friend about this exact topic (diagnosing GIN pending list updates) at PGCon 2019 in Ottawa[1][2].<p>What you need to know is that the pending list will be merged with the main b-tree during several operations. Only one of them is so extremely critical for your insert performance - that is during actual insert. Both vacuum and autovacuum (including autovacuum analyze but not direct analyze) will merge the pending list. So frequent autovacuums are the first thing you should tune. Merging on insert happens when you exceed the gin_pending_list_limit. In all cases it is also interesting to know which memory parameter is used to rebuild the index as that inpacts how long it will take: work_mem (when triggered on insert), autovacuum_work_mem (when triggered during autovauum) and maintainance_work_mem (triggered by a call to gin_clean_pending_list()) define how much memory can be used for the rebuild.<p>What you can do is:<p>- tune the size of the pending list (like you did)<p>- make sure vacuum runs frequently<p>- if you have a bulk insert heavy workload (eg. nightly imports), drop the index and create it after inserting rows (not always makes sense business wise, depends on your app)<p>- disable fastupdate, you pay a higher cost per insert but remove the fluctuation when the merge needs to happen<p>The first thing was done in the article. However I believe the author still relies on the list being merged on insert. If vacuums were tuned aggressively along with the limit (vacuums can be tuned per table). Then the list would be merged out of bound of ongoing inserts.<p>I also had the pleasure of speaking with one main authors of GIN indexes (Oleg Bartunov) during the mentioned PGCon. He gave probably the best solution and informed me to "just use RUM indexes". RUM[3] indexes are like GIN indexes, without the pending list and with faster ranking, faster phrase searches and faster timestamp based ordering. It is however out of the main PostgreSQL release so it might be hard to get it running if you don't control the extensions that are loaded to your Postgres instance.<p>[1] - video <a href="https://www.youtube.com/watch?v=Brt41xnMZqo&t=1s" rel="nofollow">https://www.youtube.com/watch?v=Brt41xnMZqo&t=1s</a><p>[2] - slides <a href="https://www.pgcon.org/2019/schedule/attachments/541_Let's%20(D)Trace%20Postgres%20tracing%20the%20madness.pdf" rel="nofollow">https://www.pgcon.org/2019/schedule/attachments/541_Let's%20...</a><p>[3] - <a href="https://github.com/postgrespro/rum" rel="nofollow">https://github.com/postgrespro/rum</a>
This seems like an instance where BPF could shine. If I had a large magic wand, I’d love to have distributed traces of database query execution with spans or events for significant events like the GIN pending list cleanup described in the article.
As a programmer, the takeaway for me is that the exceptional treatment of this database request should be logged somewhere. Here, the EXPLAIN response would have been a good place.