>, >=, =, <, <=, IF NULL and BETWEEN on a key.SELECT * FROM tablename WHERE keypart1=1 AND key_part2 > 5;SELECT * FROM tablename WHERE keypart1 IS NULL;SELECT * FROM tablename WHERE keypart1 LIKE 'jani%'SELECT * from t1,t2 where t1.col=t2.key_partSELECT MIN(keypart2),MAX(keypart2) FROM tablename where keypart1=10ORDER BY or GROUP BY on a prefix of a key.SELECT * FROM foo ORDER BY keypart1,keypart2,key_part3SELECT keypart3 FROM tablename WHERE key_part1=1key_part1 is evenly distributed between 1 and 100, it's not good to use an index in the following query:SELECT * FROM tablename where keypart1 > 1 and key_part1 < 90=ORDER BY on a HEAP tableSELECT * FROM tablename WHERE keypart2=1SELECT * FROM tablename WHERE keypart1 LIKE '%jani%'SELECT * from tablename WHERE keypart1 = # ORDER BY key2Use EXPLAIN on every query that you think is too slow!
EXPLAIN SELECT t3.date_of_action, t1.transaction_id
FROM t1 JOIN t2 JOIN t3
WHERE t2.id = t1.transaction_id
AND t3.id = t2.group_id
ORDER BY t3.date_of_action, t1.transaction_id;
| table | type | possible_keys | key | key_len | ref | rows | Extra | |
|---|---|---|---|---|---|---|---|---|
| t1 | ALL | NULL | NULL | NULL | NULL | 11 | Using temporary; Using filesort | |
| t2 | ref | id | id | 4 | t1.transaction_id | 13 | ||
| t3 | eq_ref | PRIMARY | PRIMARY | 4 | t2.group_id | 1 |
Types ALL and range signal a potential problem.
Use SHOW processlist to find out what is going on:
| Id | User | Host | db | Command | Time | State | Info | |
|---|---|---|---|---|---|---|---|---|
| 6 | monty | localhost | bp | Query | 15 | Sending data | SELECT * FROM station,station AS s1 | |
| 8 | monty | localhost | Query | 0 | SHOW PROCESSLIST |
Use KILL in mysql or mysqladmin to kill off runaway threads.
Run the following commands and try to understand the output:
SHOW VARIABLES;SHOW COLUMNS FROM ...\GEXPLAIN SELECT ...\GFLUSH STATUS;SELECT ...;SHOW STATUS;SELECT and INSERT at the same time.INSERT on a table with deleted rows, combined with SELECTS that take a long time.HAVING on things you can have in a WHERE clause.JOINS without using keys or keys which are not unique enough.JOINS on columns that have different column types.=WHERE clause with UPDATE or DELETE in the MySQL monitor. If you tend to do this, use the --i-am-a-dummy option to the mysq client.LOCK TABLES (Works on all table types)GETLOCK()/RELEASELOCK()ALTER TABLE also does a table lock on BDB tables.LOCK TABLES gives you multiple readers on a table or one writer.WRITE lock has higher priority than a READ lock to avoid starving the writers. For writers that are not important one can use the LOW_PRIORITY keyword to let the lock handler prefer readers.UPDATE LOW_PRIORITY SET value=10 WHERE id=10;
Note that you can always comment out a MySQL feature to make the query portable:
SELECT /*! SQL_BUFFER_RESULTS */ ...
SELECT SQL_BUFFER_RESULTS ...SELECT SQLSMALLRESULT ... GROUP BY ...SELECT SQLBIGRESULT ... GROUP BY ...SELECT STRAIGHT_JOIN ...SELECT ... FROM tablename [USE INDEX (indexlist) | IGNORE INDEX (indexlist)] tablename2Forces MySQL to use/ignore the listed indexes.
LOCK TABLES trans READ, customer WRITE;
SELECT sum(value) FROM trans WHERE customer_id=some_id;
UPDATE customer SET total_value=sum_from_previous_statement WHERE customer_id=some_id;
UNLOCK TABLES;
BEGIN WORK;
SELECT sum(value) FROM trans WHERE customer_id=some_id;
UPDATE customer SET total_value=sum_from_previous_statement WHERE customer_id=some_id;
COMMIT;
Note that you can often avoid transactions altogether by doing:
UPDATE customer SET value=value+new_value WHERE customer_id=some_id;
REPLACE works exactly like INSERT, except that if an old record in the table has the same value as a new record on a unique index, the old record is deleted before the new record is inserted. Instead of using
SELECT 1 FROM t1 WHERE key=#
IF found-row
LOCK TABLES t1
DELETE FROM t1 WHERE key1=#
INSERT INTO t1 VALUES (...)
UNLOCK TABLES t1;
ENDIF
Do
REPLACE INTO t1 VALUES (...)
--skip-locking (default on some OSes) if possible. This will turn off external locking and will give better performance.application-level hashed values instead of using long keys:SELECT *
FROM table_name
WHERE hash = MD5(concat(col1,col2))
AND col_1='constant'
AND col_2='constant'
CHECK and REPAIR table.GROUP BY and DISTINCTLEFT JOIN ... IF NULL optimization.CREATE TABLE ... SELECTCREATE TEMPORARY table_name (...)RENAME (RENAME TABLE foo as fooold, foonew AS foo)MERGE TABLES