HeatWare Tech Tips for Windows, Linux, Databases, Java, and PHP

JSONB vs JSON in PostgreSQL, Measured

Two curly-brace blocks: left, loose unordered chips (json); right, a structured tree with an index (jsonb) in PostgreSQL

Use jsonb. It gets containment (@>), key-existence (?), path queries, equality, and GIN indexing; json has none of those and exists to store your input byte-for-byte. Pick json only when exact text matters — key order, duplicate keys, whitespace. The PostgreSQL docs say the same: prefer jsonb unless you have “legacy assumptions about ordering of … Read more

PgBouncer vs Pgpool-II: Tested on PostgreSQL 17

Many client connections funnel into a pooler that routes to database cylinders: PgBouncer versus Pgpool-II

Use PgBouncer when the problem is “too many connections”: it is a single small process that multiplexes thousands of client connections onto a handful of server ones. Use Pgpool-II when you need a routing layer in front of several PostgreSQL servers — read load balancing, automatic failover — and accept operating something closer to a … Read more

Tune MySQL ‘Join’ Buffers for Better Query Performance

MySQL performance tuning illustration

In MySQL 8.0.20 and later, join_buffer_size sizes the hash join buffer. It is not a dial you turn for a smooth percentage gain — on the workload measured below it did nothing until the buffer was large enough for the hash table to stop spilling to disk, then it stopped mattering again. Find your own … Read more

How to Create Temporary Tables in MySQL with Examples

MySQL database server illustration

Create a TEMPORARY table with CREATE TEMPORARY TABLE name (…) — it’s visible only in the session that created it, disappears when that session ends, and can share a name with a permanent table without an error (it shadows it, which is the part most guides skip). Below is real output from MySQL 8.4.10 for … Read more

How to Find and Prevent MySQL Deadlocks Easily

Database performance monitoring illustration

A MySQL deadlock is two transactions each holding a row lock the other one needs next — InnoDB’s deadlock detector picks one, kills it with error 1213, and the other proceeds. Below is a real one, caused on purpose on a live MySQL 8.4.10 server: two connections locking the same two rows in opposite order, … Read more

MySQL in Docker: Root Password Off the Command Line

mysql best practices and tips running on docker

Keep the MySQL root password off the docker run command line: instead of -e MYSQL_ROOT_PASSWORD=…, set MYSQL_ROOT_PASSWORD_FILE to the path of a Docker secret or a bind-mounted file. The official mysql image’s initialization script loads the password from that file (Docker Hub’s text is quoted below). Honesty first: this machine has no Docker installed, and … Read more

MySQL Incremental Backups with Custom Scripts: Binlog Slices

mysql incremental backups examples and how to guide

A mysqldump –all-databases into a dated directory every night is a full backup, not an incremental one. And applying an incremental by piping mysqlbinlog output into mysql database_name silently does not restore it. Both are reproduced below on MySQL 8.4.10. An incremental backup in MySQL is a slice of the binary log, and it is … Read more

How to Secure MySQL: Setting Up SSL/TLS

MySQL database server illustration

MySQL 8.4 already encrypts in transit: it auto-generates a CA and server certificate in the data directory the first time it starts, and a stock 8.4.10 negotiates a real TLSv1.3 connection with zero configuration. The hardening step that is not the default is require_secure_transport=ON — until you set it, plaintext connections still succeed. Generate your … Read more

MySQL Horizontal vs Vertical Scaling: Bigger Box First

MySQL database illustration

Try a bigger box (vertical scaling) first. Partition next if the problem is one huge table with one slow query shape, and add replicas if it is read volume rather than table size. Shard last, and only once you’ve measured that a single server’s write throughput, not query shape, is the wall. Sizing a bigger … Read more

InnoDB vs. MyISAM: MySQL Performance Compared

MySQL database server illustration

Use InnoDB unless you have a specific, tested reason not to — it’s the default engine in MySQL 8.4, it’s the only one of the two with transactions, row-level locking, foreign keys, and crash recovery, and since MySQL 5.6 it also does full-text search, which used to be MyISAM’s one exclusive feature. The sections below … Read more

MySQL Query Optimization Strategies To Improve Performance

MySQL performance tuning illustration

An index doesn’t make a query faster in the abstract — it changes the plan MySQL chooses, and EXPLAIN ANALYZE proves it. On a 500,000-row table, filtering on an unindexed column costs 50000 and takes ~100ms; the same filter after an index costs 875 and takes ~3ms. Below is that comparison unedited, plus a note … Read more

Monitoring MySQL 8.4 Without Installing Anything

Database performance monitoring illustration

MySQL 8.4 already ships the monitoring most people install a tool for. performance_schema and the sys schema are on by default and answer “what’s slow” and “what’s using memory” without installing anything. What follows is real output from this machine’s server. What’s actually running, right now The single most useful query for “what is my … Read more

MySQL Scale-Out: A Real Replication Setup, Tested

MySQL database illustration

“performance tuning” (buffer pool sizing, query indexing) is scaling up — a bigger, better-tuned single server. This page is about scaling out: adding replicas so more than one server can serve reads. If you have not yet decided which of those you need, the choice breaks into three independent decisions, and read volume is only … Read more

Use Prepared Statements to Boost PostgreSQL Performance

PostgreSQL performance illustration

PREPARE saves PostgreSQL from re-parsing and re-planning a query on every execution — but past the fifth call it may silently swap in a generic, parameter-unaware plan instead of continuing to plan around your actual values, controlled by plan_cache_mode. That switch is the real performance story here, and it’s demonstrated below with unedited EXPLAIN output … Read more

PostgreSQL Materialized Views: Refresh, Locks, CONCURRENTLY

Database server performance illustration

A materialized view stores the result of a query on disk. You query it like a table, and it stays stale until you run REFRESH MATERIALIZED VIEW: CREATE MATERIALIZED VIEW daily_sales AS SELECT date_trunc(‘day’, created_at) AS day, count(*) AS orders, sum(amount) AS revenue FROM orders GROUP BY 1; REFRESH MATERIALIZED VIEW daily_sales; Two things decide … Read more

MySQL Buffer Pool Performance Tuning Guide

MySQL performance tuning illustration

MySQL’s own manual gives one sizing rule: “On a dedicated database server, you might set the buffer pool size to 80% of the machine’s physical memory size.” If the server was started with –innodb-dedicated-server, you don’t even set it — MySQL calculates it for you. Everything below is either a command run against a real … Read more

PostgreSQL Stored Procedures vs Functions: CALL and COMMIT

Database performance monitoring illustration

A PostgreSQL procedure is created with CREATE PROCEDURE, invoked with CALL, and may run COMMIT and ROLLBACK inside its own body. A function cannot. That is the whole reason procedures exist, and it is the one thing a function can never be rewritten to do: CREATE FUNCTION f_commit() RETURNS void LANGUAGE plpgsql AS $$ BEGIN … Read more

LVM Snapshots Are Not Version Control

lvm linux

An LVM snapshot is not a backup, and calling it “version control” is the part of this page most likely to cost you data. A classic (non-thin) LVM snapshot lives in the same volume group as the volume it snapshots, shares its fate if that volume group’s storage fails, and — this is the part … Read more

PostgreSQL CTEs: Inlined vs MATERIALIZED

postgresql common table expressions (CTE) examples and guide

Since PostgreSQL 12, a plain, non-recursive, side-effect-free WITH CTE referenced once is inlined into the surrounding query by default — the planner treats it the same as an equivalent subquery, filters can push down into it, and it produces an identical plan. Before 12, a CTE was always an optimization fence: computed once, in isolation, … Read more

How to Use Rsync for Backups and File Syncing in Linux

backup files using rsync on linux

For a nightly incremental backup, use this: rsync -a –delete –link-dest=/backup/previous /source/directory/ /backup/2026-08-09/ Please read this first. Do not build a backup on –ignore-existing: rsync -av –ignore-existing /source/directory/ /backup/directory/ skips updating files that already exist at the destination, so modified files are never transferred. If you built a nightly job from that command, your backup … Read more

NFS vs. Samba: Linux File Sharing Explained

learn about linux file sharing using NFS and SAMBA

Choose on authentication, not throughput. Samba joined to a domain authenticates the user — Kerberos or NTLMv2, per connection. NFS with sec=sys, the default, authenticates the host, and only by source port. If your clients are machines you fully control on a segment you fully control, NFS is simpler and defensible; for anything else, use … Read more

PostgreSQL Sharding vs Partitioning: What’s Built In

postgresql data partitioning and sharding

Partitioning splits one big table into smaller pieces on one PostgreSQL server; sharding splits data across multiple servers. Partitioning is native — CREATE TABLE … PARTITION BY ships in core PostgreSQL. Sharding is not: core PostgreSQL has no built-in sharding, full stop. Getting there means an extension (Citus, not installed here) or building it yourself … Read more