Skip to content

MySQL Interview Questions

What is the difference between MyISAM and InnoDB?

FeatureMyISAMInnoDB
TransactionsNoYes (ACID)
Foreign keysNoYes
Row-level lockingNo (table-level)Yes
Full-text searchYesYes (5.6+)
Default sinceMySQL 5.5MySQL 5.5+

InnoDB is the default and recommended engine for most applications.


What is the difference between CHAR and VARCHAR?

  • CHAR(n) โ€” fixed-length, always uses n bytes. Faster for fixed-size data (e.g., country codes).
  • VARCHAR(n) โ€” variable-length, uses only as much space as needed plus 1-2 bytes for length. Better for strings of variable size.

What are the different types of JOINs?

-- INNER JOIN: only matching rows in both tables
SELECT o.id, c.name
FROM orders o
INNER JOIN customers c ON o.customer_id = c.id;
-- LEFT JOIN: all rows from left, matching from right (NULL if no match)
SELECT c.name, o.id
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id;
-- RIGHT JOIN: all rows from right, matching from left
SELECT c.name, o.id
FROM customers c
RIGHT JOIN orders o ON c.id = o.customer_id;
-- CROSS JOIN: cartesian product
SELECT a.name, b.name
FROM employees a
CROSS JOIN departments b;

What is an index and when should you use one?

An index is a data structure that speeds up SELECT queries at the cost of slower INSERT/UPDATE/DELETE and extra storage.

Use indexes on:

  • Columns in WHERE clauses
  • Columns used in JOIN conditions
  • Columns in ORDER BY or GROUP BY
  • Foreign key columns
CREATE INDEX idx_orders_customer ON orders(customer_id);
CREATE UNIQUE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_composite ON orders(customer_id, created_at);

What is the difference between a clustered and non-clustered index?

  • Clustered index โ€” the table data is physically stored in the order of this index. InnoDB uses the primary key as the clustered index automatically.
  • Non-clustered index โ€” a separate structure with pointers to the actual rows. All non-primary indexes in InnoDB are non-clustered.

What is a covering index?

A covering index contains all the columns a query needs, so MySQL can satisfy the query from the index alone without touching the table data:

-- Query
SELECT customer_id, created_at FROM orders WHERE customer_id = 5;
-- Covering index โ€” both columns are in the index
CREATE INDEX idx_covering ON orders(customer_id, created_at);

What are the ACID properties?

  • Atomicity โ€” all operations in a transaction succeed or all are rolled back
  • Consistency โ€” the database moves from one valid state to another
  • Isolation โ€” concurrent transactions donโ€™t interfere with each other
  • Durability โ€” committed transactions survive crashes

What are transaction isolation levels?

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
LevelDirty ReadNon-Repeatable ReadPhantom Read
READ UNCOMMITTEDYesYesYes
READ COMMITTEDNoYesYes
REPEATABLE READ (default)NoNoYes
SERIALIZABLENoNoNo

What is a deadlock?

Two transactions each hold a lock the other needs, causing both to wait forever. MySQL detects deadlocks and rolls back one transaction automatically.

-- Transaction 1 -- Transaction 2
BEGIN; BEGIN;
UPDATE accounts SET bal=... UPDATE accounts SET bal=...
WHERE id = 1; WHERE id = 2;
-- waits for lock on id=2 -- waits for lock on id=1
-- DEADLOCK detected

Prevention: always acquire locks in the same order.


How do you analyze a slow query?

EXPLAIN SELECT * FROM orders WHERE customer_id = 5;
EXPLAIN ANALYZE SELECT * FROM orders WHERE customer_id = 5;

Key columns to check:

  • type: ALL (full scan, bad) โ†’ ref or const (index use, good)
  • rows: estimated rows examined โ€” lower is better
  • Extra: Using filesort or Using temporary are warning signs

What is query caching and is it recommended?

MySQLโ€™s query cache was deprecated in MySQL 5.7 and removed in MySQL 8.0. It caused significant contention. Use application-level caching (Redis, Memcached) instead.


-- Stored Procedure
DELIMITER //
CREATE PROCEDURE GetOrdersByCustomer(IN cust_id INT)
BEGIN
SELECT * FROM orders WHERE customer_id = cust_id;
END //
DELIMITER ;
CALL GetOrdersByCustomer(42);
-- Function
DELIMITER //
CREATE FUNCTION CalculateDiscount(price DECIMAL(10,2), pct INT)
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN
RETURN price * (1 - pct / 100);
END //
DELIMITER ;
SELECT CalculateDiscount(100.00, 20); -- returns 80.00

-- Show databases and tables
SHOW DATABASES;
SHOW TABLES;
DESCRIBE orders;
-- Check indexes
SHOW INDEX FROM orders;
-- Check slow queries
SHOW VARIABLES LIKE 'slow_query_log%';
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
-- Table size
SELECT table_name,
ROUND((data_length + index_length) / 1024 / 1024, 2) AS size_mb
FROM information_schema.tables
WHERE table_schema = 'mydb'
ORDER BY size_mb DESC;