-- Create index on multiple columnsCREATE INDEX idx_dept_salary ON employees(department_id, salary);-- Follows leftmost prefix ruleSELECT * FROM employees WHERE department_id = 10 AND salary > 5000; -- Uses indexSELECT * FROM employees WHERE salary > 5000; -- Doesn't use index (missing leftmost column)
Leftmost Prefix Rule: Composite index (a, b, c) works for:
-- Enforce uniquenessCREATE UNIQUE INDEX idx_email ON users(email);-- Or in table definitionCREATE TABLE users ( id INT PRIMARY KEY, email VARCHAR(100) UNIQUE);
-- Force index usageSELECT * FROM employees FORCE INDEX (idx_salary)WHERE salary > 8000;-- Ignore specific indexSELECT * FROM employees IGNORE INDEX (idx_age)WHERE age > 30;
-- BAD: Function on indexed columnSELECT * FROM employees WHERE YEAR(hire_date) = 2020;-- GOOD: Rewrite without functionSELECT * FROM employees WHERE hire_date >= '2020-01-01' AND hire_date < '2021-01-01';-- BAD: Implicit type conversionSELECT * FROM users WHERE phone = 13800138000; -- phone is VARCHAR-- GOOD: Explicit type matchSELECT * FROM users WHERE phone = '13800138000';-- BAD: Leading wildcardSELECT * FROM users WHERE name LIKE '%zhang%';-- GOOD: Prefix matchSELECT * FROM users WHERE name LIKE 'zhang%';
-- Start transactionSTART TRANSACTION;-- orBEGIN;-- Execute operationsUPDATE accounts SET balance = balance - 100 WHERE id = 1;UPDATE accounts SET balance = balance + 100 WHERE id = 2;-- Commit changesCOMMIT;-- Or rollback if errorROLLBACK;
START TRANSACTION;UPDATE accounts SET balance = balance - 100 WHERE id = 1;SAVEPOINT sp1;UPDATE accounts SET balance = balance + 100 WHERE id = 2;SAVEPOINT sp2;UPDATE accounts SET balance = balance - 50 WHERE id = 3;-- Rollback to savepointROLLBACK TO sp2;COMMIT;
-- Shared lock (S lock) - Read lockSELECT * FROM users WHERE id = 1 LOCK IN SHARE MODE;-- Exclusive lock (X lock) - Write lockSELECT * FROM users WHERE id = 1 FOR UPDATE;
-- Check buffer pool sizeSHOW VARIABLES LIKE 'innodb_buffer_pool_size';-- Set buffer pool size (in bytes)SET GLOBAL innodb_buffer_pool_size = 2147483648; -- 2GB
Buffer Pool Benefits:
Caches frequently accessed pages
Reduces disk I/O
Improves query performance
Recommended buffer pool size: 60-80% of available RAM for dedicated DB servers
-- Use LIMIT for paginationSELECT * FROM users ORDER BY created_at DESCLIMIT 20 OFFSET 0;-- Better: Use WHERE with indexSELECT * FROM users WHERE id > 1000ORDER BY id LIMIT 20;
-- Less efficientSELECT * FROM employees WHERE department_id IN (SELECT id FROM departments WHERE name = 'IT');-- More efficientSELECT * FROM employees eWHERE EXISTS ( SELECT 1 FROM departments d WHERE d.id = e.department_id AND d.name = 'IT');
-- Use small table as driving tableSELECT /*+ LEADING(d e) */ e.name, d.department_nameFROM departments dINNER JOIN employees e ON d.id = e.department_idWHERE d.name = 'IT';
Join Limit: Avoid joining more than 3 tables. For complex queries, consider:
✓ Columns in WHERE clauses
✓ Columns in JOIN conditions
✓ Columns in ORDER BY/GROUP BY
✓ Foreign key columns
✓ Frequently queried columns
When NOT to Create Indexes
✗ Columns with few distinct values
✗ Tables with frequent INSERT/UPDATE/DELETE
✗ Columns rarely used in queries
✗ Small tables (< 1000 rows)
✗ Columns with large data types (TEXT, BLOB)
Composite Index Order
Order columns by:
Equality conditions (equals)
Range conditions (greater than, less than, BETWEEN)
-- Enable slow query logSET GLOBAL slow_query_log = ON;SET GLOBAL long_query_time = 2; -- Queries > 2 secondsSET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';-- Check slow queriesSHOW GLOBAL STATUS LIKE 'Slow_queries';
-- Analyze table to update statisticsANALYZE TABLE employees;-- Show index cardinalitySHOW INDEX FROM employees;-- Check index usageSELECT * FROM sys.schema_unused_indexes;