#Performance

Speed Up Screen Recordings While Keeping the Original Clock
How to make a timelapse from a screen recording by speeding up idle sections more than active sections, using split, trim, and setpts, then joining them with concat. The main trap is that drawtext must come before setpts for the clock to follow the original timeline instead of the accelerated one.

Images Fail on Mobile in Pages Hidden with display:none
A site switches pages using display:none, but opening another page on mobile leaves blank black images, even though the files return 200 and both fetch and new Image succeed. The culprit is the IntersectionObserver behind loading=lazy not firing when the page changes from none to block, and simply setting loading=eager is still not enough.

Moving JSON Time Series to Columns Without Changing the Dashboard
I stored entire device frames as JSON arrays at one row per second. After two weeks, the tables had grown to 183 MB at the endpoint and 625 MB on the server, with JSON_EXTRACT queries that could not use an index — here is how I moved the data into int columns and had the API rebuild a sparse array without changing a single line of the dashboard.

Moving Computation from PHP to the Browser: 12 Seconds to 12 ms
A single page ran tens of thousands of subqueries and took 12 seconds to load. I fixed it by precomputing a summary table, sending a single 107 KB dataset, and moving the formulas to the browser, bringing computation down to 12 milliseconds, with a parity test that requires JS results to match PHP on every row.

Laravel Queues on Shared Hosting — Don't Share Redis with Cache
If you're enabling queues for Laravel on shared hosting and planning to separate the queue from cache with different REDIS_DB numbers, that won't help. maxmemory and eviction apply to the whole instance, not individual DBs. This article explains why I chose the database driver instead, with complete systemd units to replace Supervisor.

MariaDB on defaults — a 128M buffer pool on a 55 GB RAM server
A 16 core server with 55 GB RAM and an SSD, but MariaDB still had the default 128 MB buffer pool. The result was 50 million disk reads in 5 days. The full before-and-after settings, service name and config path traps on DirectAdmin/Debian, rollback steps, and another 500 MyISAM tables waiting for conversion.

AI Crawler Overloads ?add-to-cart= — Block It Without Hurting SEO
Server load triggered an email alert. The logs showed that 84% of the day's traffic came from one AI crawler following add-to-cart links for every product. I added layers of protection with robots.txt, rel=nofollow and nginx limit_req while keeping all product pages indexable.

Bulk Import Legacy .xls Files into Laravel with PhpSpreadsheet
Legacy .xls files with Thai headers encoded in tis-620 have unreadable column names, large files make PhpSpreadsheet exhaust memory and crash, and files users merge themselves contain duplicate rows — use column positions instead of names, add a read filter, and deduplicate with a natural key.

Charset Mismatch Silently Kills JOIN Indexes — an utf8mb4 Mirror
The old database uses tis620 and the new one uses utf8mb4. JOIN across databases, and every index immediately becomes decorative without a single error — how to prove it with EXPLAIN and build a mirror that converts tis620 to utf8mb4 during the dump, plus the sed trap that silently breaks tables.

One Query Hung for 54 Minutes, Causing Sitewide 504s via MyISAM Locks
A single 30 MB table caused 504s on every page across the site, even with 9.5 GB of RAM still free — I traced information_schema.PROCESSLIST to a single SELECT that had been stuck for 54 minutes on a MyISAM table, cascading into metadata locks across the server, with an immediate fix and ways to prevent it from happening again.