TechEarl
Topic · Database

Database

SQL that runs, indexes that earn their keep, and migrations that don't take the site down.

47 articlesWritten by Ishan Karunaratne
Database tutorials for MySQL, MariaDB, schema migrations, indexes, and query performance.
Elasticsearch 9.x cheat sheet: index and document operations, Query DSL, aggregations, vector / kNN search, ESQL, cluster management, and common mistakes.
FeaturedDatabase

Elasticsearch Cheat Sheet

Practitioner reference for Elasticsearch 9.x: index and document operations, Query DSL, aggregations, vector / kNN search, ESQL, cluster management, version compatibility notes, and the gotchas that bite first-time operators.

More in Database
Open vintage hardcover reference manual on a dark slate desk, dense columned print on warm cream pages lit by a single warm amber side lamp

MySQL Cheat Sheet

MySQL cheat sheet covering CLI commands, database and table operations, joins, indexes, backups, user management, and transactions, with version notes for 5.7, 8.0, and 8.4.

Upgrade MySQL 8.0 to 8.4 LTS: removed deprecated options, authentication_policy variable, mysql_native_password disabled by default, in-place upgrade procedure.

How to Upgrade MySQL 8.0 to 8.4 LTS

MySQL 8.4 is the new LTS branch, with Premier Support through April 2029 and Extended Support through April 2032. The 8.0 to 8.4 upgrade is much smaller than 5.7 to 8.0, but removed options and the new authentication_policy variable still bite. Full procedure with rollback.

Full migration from MySQL 5.7 to 8.0: prerequisites, mysqlcheck dry-run, in-place upgrade, authentication-plugin caching_sha2_password switch, and rollback.

How to Migrate from MySQL 5.7 to 8.0 (Step-by-Step)

MySQL 5.7 has been past its EOL since October 2023. Here is the migration to 8.0: prerequisites, dry-run with mysqlcheck, in-place upgrade, the authentication-plugin change that breaks old clients, and rollback if it goes sideways.

Macro photograph of an old metal ruler being replaced by a longer brass measuring tape on a dark slate workbench, single warm side light

How to Change a MySQL Column Type

Change a MySQL column type with ALTER TABLE MODIFY or CHANGE. Covers data preservation, CAST behavior, INT to BIGINT, VARCHAR widening, and how ALGORITHM applies.

Macro photograph of a printer's typecase drawer with brass-and-wood compartments, one new compartment freshly added at the end, single warm side light

How to Add a Column to a MySQL Table

Add a column to a MySQL table with ALTER TABLE ADD COLUMN. Covers DEFAULT values, NOT NULL on existing rows, AFTER positioning, and ALGORITHM=INSTANT on MySQL 8.0.12+.

Elasticsearch zero-downtime reindex with the alias-swap pattern: change mapping, reindex, atomically swap the alias, no search outage. Bash script for execute + rollback. Verified on 8.x and 9.x.

How to Reindex Elasticsearch with Zero Downtime

The alias-swap pattern I use in production to change Elasticsearch mappings without taking the search down. Walks through the five steps, gives you a parameterized bash script that runs the reindex and rolls back if needed, and verifies the technique against Elasticsearch 8.x and 9.x.

Macro photograph of a stack of paper documents on a dark slate desk with a single sheet pulled out and crumpled to the side, warm amber side light

How to Delete Duplicate Rows in MySQL

Delete duplicate rows in MySQL while keeping one per group, using DELETE JOIN, ROW_NUMBER with CTE, or the safe temp-table swap. With dry-run, transactions, and rollback.

Macro photograph of two near-identical brass keys laid side by side on a dark slate surface under a single warm side light, slight reflection on the metal, shallow depth of field, moody editorial mood

How to Find Duplicate Rows in MySQL

Find duplicate rows in MySQL with GROUP BY HAVING, a ROW_NUMBER window function, or a self-join. Includes NULL behaviour, soft duplicates, and the right index.

Macro photograph of two brass interlocking gears on a dark slate workbench, teeth perfectly meshed, single warm side lamp lighting the metal

How to JOIN Two MySQL Tables

JOIN two MySQL tables with INNER, LEFT, and RIGHT JOIN. With a real example, when each one matches, and the duplicate-row multiplication mistake everyone makes once.

How to store money in MongoDB: why the BSON double drifts, the Decimal128 type for exact decimal amounts, integer cents in a NumberLong for high-volume ledgers, and a separate ISO 4217 currency field.

How to Store Money in MongoDB: Decimal128 vs Integer Cents

Never store money as a BSON double. Use the Decimal128 type for exact decimal amounts, or store integer cents in a 64-bit NumberLong for high-volume ledgers, and always keep the ISO 4217 currency code in its own field. Comparison, worked documents, and the NumberDecimal string gotcha.

Macro photograph of a paper invoice with carbon-copy receipts being fed into an old card-reader on a dark slate desk, warm amber side lamp

How to Import a CSV File Into MySQL

Import a CSV into MySQL using LOAD DATA INFILE, LOAD DATA LOCAL INFILE, or the mysqlimport command. Covers header rows, encoding, the FILE privilege, and broken CSVs.

How to store an array in PostgreSQL: native array column types declared with [], the curly-brace and ARRAY[...] literal forms, containment and overlap queries with @> and &&, ANY() membership, and a GIN index.

How to Store an Array in PostgreSQL

PostgreSQL has native array types: any base type can be an array, declared with []. How to insert with the curly-brace literal or ARRAY[...], query with @>, &&, and ANY(), index with GIN, and when an array beats a junction table or jsonb.

Macro photograph of a printed spreadsheet ledger on a dark slate desk, neat columns of numbers in monospaced print, single warm side lamp grazing the page edge

How to Export a MySQL Table to CSV

Export a MySQL table to CSV using SELECT INTO OUTFILE, mysqldump --tab, the mysql client with a piped redirect, or a no-privilege one-liner that works on hosts where FILE is disabled.

How to store an Argon2id password hash in MySQL: use VARCHAR(255) for the variable-length encoded string, never a fixed CHAR(60), with the hash computed in the application via PHP password_hash, Python argon2-cffi, or the Node argon2 package.

How to Store an Argon2 Password Hash in MySQL

Store an Argon2id password hash in MySQL or MariaDB the right way: VARCHAR(255), never a fixed-width column. The encoded format, why its length varies, computing it in PHP / Python / Node, OWASP parameters, and a worked users schema.

Convert every MyISAM table to InnoDB: why MyISAM is dead (no transactions, no FKs, crash-unsafe), the ALTER TABLE syntax, FULLTEXT considerations, and a script to convert all tables in a database.

MySQL MyISAM to InnoDB Conversion: Why and How

MyISAM has no transactions, no foreign keys, and corrupts on crash. InnoDB has been the MySQL default since 5.5 and is the only engine that gets new features. Here is how to convert every MyISAM table in a MySQL database with a single SQL script.

How to store a UUID in MySQL with storage and index-size trade-offs: CHAR(36) versus the recommended BINARY(16), the UUID_TO_BIN/BIN_TO_UUID functions, the swap_flag trick, and why random UUID primary keys hurt InnoDB insert performance.

How to Store a UUID in MySQL: BINARY(16) vs CHAR(36)

How to store a UUID in MySQL or MariaDB: the readable CHAR(36) string or the BINARY(16) you should usually reach for. Storage cost, index size, UUID_TO_BIN/BIN_TO_UUID, the swap_flag trick, and why random UUID primary keys wreck InnoDB inserts.

How to store JSON in PostgreSQL: the json type's exact text copy versus the jsonb decomposed binary format, the containment and key-existence operators, and indexing a jsonb column with a GIN index.

How to Store JSON in PostgreSQL: json vs jsonb

PostgreSQL has two JSON types. json keeps an exact text copy and reparses on every read; jsonb stores a decomposed binary format you can index with GIN. When to use each, the operators, and a worked products schema with a containment index.

How to store JSON in MySQL: the native JSON column type versus a TEXT column, validation on insert, the ->> path operator, and indexing JSON with a generated column.

How to Store JSON in MySQL: The JSON Type vs TEXT

MySQL has a native JSON column type that validates on insert, stores a parsed binary format, and gives you path operators like ->>. When to reach for it over TEXT, how to index it with a generated column, and the MariaDB difference.

How to store a phone number in MySQL: use VARCHAR not an integer, normalize to E.164 format, store it in VARCHAR(16), index for lookups, and keep the raw user input alongside it.

How to Store a Phone Number in MySQL

Store a phone number in MySQL as a string, never an integer. Normalize to E.164 and use VARCHAR(16), index it for lookups, and keep the raw input in a second column. Worked schema for MySQL and MariaDB.

How to store money in MySQL: why FLOAT and DOUBLE drift, DECIMAL(19,4) for exact fixed-point amounts, BIGINT integer cents for high-volume ledgers, and a separate CHAR(3) ISO 4217 currency column.

How to Store Money in MySQL: DECIMAL vs Integer Cents

Never use FLOAT or DOUBLE for money. Use DECIMAL(19,4) for exact fixed-point amounts, or BIGINT integer cents for high-volume ledgers, and always store the ISO 4217 currency code separately. Comparison, worked schema, and the rounding rules.

How to store a bcrypt password hash in PostgreSQL: the 60-character modular-crypt format, why text beats char(60), app-side hashing, the pgcrypto crypt() and gen_salt('bf') option, and a worked users-table schema.

How to Store a bcrypt Password Hash in PostgreSQL

A bcrypt hash is a fixed 60-character string. In PostgreSQL the right column is text (varchar(255) is equivalent). Why text over char(60), app-side hashing, the pgcrypto crypt() option, and a worked users schema.

What column type a password should be in MySQL: VARCHAR(255) holding the encoded bcrypt or argon2id hash, why CHAR(60) and VARCHAR(60) and TEXT are wrong, and the lookup-then-verify flow.

What Column Type Should a Password Be in MySQL?

The column type for a password in MySQL is VARCHAR(255). You store the encoded output of a slow password hash (bcrypt, argon2id, scrypt), never a raw MD5 or SHA-256, and you never query the table by password.

Back up every MySQL database with mysqldump in one command. Covers --single-transaction, --routines, --events, --hex-blob, gzip compression, restoring from the dump, cron schedules, and modern alternatives (MySQL Shell, Percona XtraBackup).

How to Export All MySQL Databases with mysqldump

Back up every MySQL database in one command with mysqldump, including --single-transaction for InnoDB consistency, gzip compression, restore steps, and the modern alternatives (MySQL Shell, Percona XtraBackup).

How to store an MD5 hash in PostgreSQL with storage trade-offs: the recommended 16-byte bytea, the readable text/char(32) hex string, and the uuid trick, plus encode()/decode() and the pgcrypto digest() function.

How to Store an MD5 Hash in PostgreSQL: bytea vs text

How to store an MD5 hash in PostgreSQL: the raw 16-byte bytea you should usually reach for, the readable text/char(32) hex string, and the uuid trick. Storage cost, encode()/decode() instead of HEX/UNHEX, and the pgcrypto digest() function.