>
, >=
, =
, <
, <=
, 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_part
SELECT MIN(keypart2),MAX(keypart2) FROM tablename where keypart1=10
ORDER BY
or GROUP BY
on a prefix of a key.SELECT * FROM foo ORDER BY keypart1,keypart2,key_part3
SELECT keypart3 FROM tablename WHERE key_part1=1
key_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=1
SELECT * FROM tablename WHERE keypart1 LIKE '%jani%'
SELECT * from tablename WHERE keypart1 = # ORDER BY key2
Use 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 ...\G
EXPLAIN SELECT ...\G
FLUSH 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)] tablename2
Forces 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 DISTINCT
LEFT JOIN ... IF NULL
optimization.CREATE TABLE ... SELECT
CREATE TEMPORARY table_name (...)
RENAME
(RENAME TABLE foo as fooold, foonew AS foo
)MERGE TABLES