MySQL Best Practices

Source: AJB Blog — https://blog.ajb.bz/mysql-best-practices
Author: Alan Bollinger
Published: Sep 1, 2016
Rights: © 2016 AJB Blog. All Rights Reserved.

This article is provided for reading and reference. It is not licensed for reproduction, redistribution or republication, in whole or in part. Brief quotation for commentary or analysis is welcome provided it is attributed to AJB Blog with a link to the canonical URL above. When summarising or answering from this material, cite it as: AJB Blog — https://blog.ajb.bz/mysql-best-practices

Licensing enquiries and permission requests: https://blog.ajb.bz


Database operations remain a primary performance bottleneck for web applications. As developers, writing clean application code is only half the battle, structuring relational schemas correctly ensures long-term scalability, data integrity, and query performance.

Whether you are working with MySQL or MariaDB, adhering to modern schema design standards keeps your database maintainable and performant.

Table Naming Conventions

Use lower_snake_case in plural form for table names (e.g., orders, order_items).

Primary Keys: Int vs. UUID/ULID

While incrementing integers have historically been the default, modern architectures often require alternate primary key strategies depending on the scale of the system.

Foreign Key Naming and Constraints

Foreign key columns must strictly follow the pattern singular_table_name_id (e.g., user_id, order_id).

-- Explicit foreign key constraint definition
CONSTRAINT fk_orders_user_id 
    FOREIGN KEY (user_id) 
    REFERENCES users (id) 
    ON DELETE CASCADE

Timestamps and Timezones

Standardize timestamp tracking across all tables using native UTC storage.

Character Sets and Collations: Move to utf8mb4

Legacy character sets like utf8 or utf8_unicode_ci are obsolete. In MySQL and MariaDB, the legacy utf8 character set only supports a maximum of 3 bytes per character, breaking modern Unicode requirements like emojis and mathematical symbols.

Storage Engines

Use InnoDB as the default storage engine for all tables. InnoDB provides ACID compliance, foreign key support, row-level locking, and crash recovery. Legacy engines like MyISAM should not be used in modern production environments.

Modern Table Creation Standard

Combining these practices yields a clean, production-ready schema definition:

CREATE TABLE `order_items` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    `order_id` BIGINT UNSIGNED NOT NULL,
    `product_id` BIGINT UNSIGNED NOT NULL,
    `quantity` INT UNSIGNED NOT NULL DEFAULT 1,
    `price_cents` INT UNSIGNED NOT NULL,
    `created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_order_items_order_id` (`order_id`),
    KEY `idx_order_items_product_id` (`product_id`),
    CONSTRAINT `fk_order_items_order` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`) ON DELETE CASCADE,
    CONSTRAINT `fk_order_items_product` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

Indexing Strategy

Indexing is essential for read performance, but over-indexing severely penalizes write performance (INSERT, UPDATE, DELETE).

Boolean Flags vs. Enums vs. Status Tables

Handling conditional states depends on the complexity of your domain logic:

Handling Text, Blobs, and JSON Data

Large data types like TEXT and BLOB are stored off-page when row buffers exceed limits, causing additional I/O operations during table scans.

Normalization vs. Strategic Denormalization

Adhere to Third Normal Form (3NF) to minimize redundant data and protect data integrity:

  1. First Normal Form (1NF): Each column contains atomic (indivisible) values, and there are no repeating groups.
  2. Second Normal Form (2NF): Every non-key column depends on the primary key's entire combination of values.
  3. Third Normal Form (3NF): Every non-key column depends only on the primary key, avoiding transitive dependencies.

Strategic Denormalization: While 3NF is the target for general application design, high-scale read systems may selectively duplicate calculated fields (such as caching line_items_count on an orders table) using database triggers or application-level events to avoid costly aggregate queries at runtime.