This document provides tips for optimizing MySQL performance for applications. It discusses good practices for the MySQL configuration file such as enabling the slow query log and performance schema. It also covers using indexes appropriately, avoiding N+1 queries, performing operations like counting and deleting in SQL rather than application code, and properly using transactions.
4. € whoami
● Federico Razzoli
● Freelance consultant
● Writing SQL since MySQL 2.23
https://federico-razzoli.com
hello@federico-razzoli.com
● I love open source, sharing,
Collaboration, win-win, etc
● I love MariaDB, MySQL, Postgres, etc
5. This talk applies to...
● MySQL
● Percona Server
● MariaDB
And most information applies, with some changes, to:
● All other relational DBMSs
6. This talk is about...
● Low hanging fruits to speed up your apps
● Hints you may want to investigate in the next days
7. This talk is not about...
● ORMs
● PHP code
● Query optimisation
● SQL_MODE
● Graphical interfaces
● MySQL characteristics that I don’t want to advertise
○ For a reason
○ But you are allowed to ask questions that I hope you
don’t ask
○ I will still say “thank you for your question”
8. Why do I want to
talk about MySQL
at a PHP event?
11. Slow log
ls -1 $( mysql -e 'SELECT @@datadir' ) | grep slow
● Empty the slow log before a test
○ echo '' > /path/to/slowlog
● Check the slow log when you want to check your queries
○ Includes query duration, rows returned and some details on the execution
plan
14. Queries with no results
SELECT *
FROM performance_schema.events_statements_summary_by_digest
WHERE
(
TRIM(DIGEST_TEXT) LIKE 'SELECT%'
OR TRIM(DIGEST_TEXT) LIKE 'CREATE%TABLE%SELECT%'
OR TRIM(DIGEST_TEXT) LIKE 'DELETE%'
OR TRIM(DIGEST_TEXT) LIKE 'UPDATE%'
OR TRIM(DIGEST_TEXT) LIKE 'REPLACE%'
)
AND SUM_ROWS_SENT = 0
AND SUM_ROWS_AFFECTED = 0
ORDER BY SUM_ROWS_EXAMINED DESC
LIMIT 10
G
18. An index is an ordered data structure
● Think to a phone book
● It is a table with an index on (last_name, first_name)
● First takeaway: the order of columns matters
● Your mind contains a pretty good SQL optimiser
● When you want to know which queries can be optimised with a certain index,
think to a phone book
19. Which queries can be optimised?
● WHERE last_name = 'Baker'
● WHERE first_name = 'Tom'
● WHERE first_name = 'Tom' AND last_name = 'Baker'
● WHERE last_name = 'Baker' AND first_name = 'Tom'
20. Rule #1:
A query can use a whole index
Or a leftmost part of an index
21. Which queries can be optimised?
● WHERE last_name = 'Baker'
● WHERE last_name <> 'Baker'
● WHERE last_name > 'Baker'
● WHERE last_name >= 'Baker'
● WHERE last_name < 'Baker'
● WHERE last_name =< 'Baker'
22. Which queries can be optimised?
● WHERE last_name > 'B' AND last_name < 'C'
● WHERE last_name BETWEEN 'B' AND 'BZZZZZZZZZZZ';
● WHERE last_name LIKE 'B%'
● WHERE last_name LIKE '%ake%'
● WHERE last_name LIKE '%r'
23. Rule #2:
You can use an index to find a value
Or a (closed/open) range
24. Which queries can be optimised?
● WHERE last_name = 'Nimoy' OR first_name = 'Leonard'
● WHERE last_name = 'Nimoy' OR last_name = 'Shatner'
26. Which queries can be optimised?
● WHERE last_name = 'Nimoy' AND first_name = 'Leonard'
● WHERE last_name = 'Nimoy' AND first_name > 'Leonard'
● WHERE last_name > 'Nimoy' AND first_name = 'Leonard'
● WHERE last_name > 'Nimoy' AND first_name > 'Leonard'
29. N + 1 problem
Don’t:
foreach row in ( SELECT * FROM author WHERE a.LIKE 'P%'; )
SELECT * FROM book WHERE author_id = ?;
Do:
SELECT a.first_name, a.last_name, b.*
FROM book b
JOIN author a
ON b.id = a.book_id
WHERE a.last_name = 'P%';
30. Count in SQL, not in PHP
Don’t:
foreach row in ( SELECT * FROM customer; )
$customer++;
Do:
SELECT count(*) FROM customer;
31. Dealing with duplicates
INSERT INTO product (id, ...) VALUES (24, ...);
INSERT IGNORE INTO product (id, ...) VALUES (24, ...);
INSERT INTO product (id, ...)
ON DUPLICATE KEY UPDATE name = 'Sonic screwdriver';
REPLACE INTO product (id, ...) VALUES (24, ...);
DELETE IGNORE ...
UPDATE IGNORE ...
32. Insert many rows
INSERT INTO user
(first_name, last_name, email)
VALUES
('William', 'Hartnell', 'first@bbc.co.uk'),
('Tom', 'Baker', 'tom@gmail.com'),
('Jody', 'Wittaker', 'first_lady@hotmail.com');
33. Insert into related tables
INSERT INTO `author` (name, surname) VALUES
('Arthur', 'Clarke');
INSERT INTO `book` (author_id, title) VALUES
(LAST_INSERT_ID(), '2001: A Space Odyssey');
34. Delete/Update many tables
DELETE `order`, user
FROM `order`
INNER JOIN `order`
ON order.user_id = user.id
WHERE user = 24;
UPDATE `order`, user
FROM `order`
INNER JOIN `order`
ON order.user_id = user.id
SET status = 'CANCELLED'
WHERE user = 24;
36. Creating table with rows
CREATE TABLE past_order LIKE `order`;
INSERT INTO past_order
SELECT * FROM `order`
WHERE status IN ('SHIPPED', 'CANCELLED');
Or:
CREATE TABLE customer
SELECT u.id, u.first_name, u.last_name
FROM user u JOIN `order` o
ON u.id = o.user_id
WHERE o.status <> 'CANCELED';
37. More info
For more info on this topic, ask Google:
Federico Razzoli "use sql properly to run less queries"
39. What are transactions?
ACID
● Atomicity
○ All writes in a transaction fail or succeed altogether.
● Consistency
○ Data always switch from one consistent point to another.
● Isolation
○ Transactions are logically sequential.
● Durability
○ Data changes persist after system failures (crashes).
40. Transactions syntax
START TRANSACTION;
SELECT … ;
UPDATE … ;
INSERT … ;
COMMIT;
START TRANSACTION;
DELETE … ;
INSERT … ;
ROLLBACK;
SET SESSION autocommit := 1; -- this is the default
DELETE … ;
41. Isolation levels
● READ UNCOMMITTED
○ You could see not-yet-committed changes.
● READ COMMITTED
○ Each query acquires a separate snapshot.
● REPEATABLE READ (default)
○ One snapshot for the whole transaction.
● SERIALIZABLE
○ Like REPEATABLE READ, but SELECTs are implicitly IN SHARE MODE
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
...
45. Use cases for READ COMMITTED?
● Delete/update rows by id from multiple tables
● Show user’s payment history
46. READ ONLY transactions
● Make sense with REPEATABLE READ
● 2 SELECTs will see consistent data
● Attempts to change data will return an error
● Performance optimisation
○ But not as much as READ UNCOMMITTED
START TRANSACTION READ ONLY;
47. Ways to kill MySQL
Having SELECT privilege is enough to kill MySQL!
(or any RDBMS)
Method 1:
START TRANSACTION;
SELECT * FROM `order`;
SELECT SLEEP(3600 * 12);
48. Ways to kill MySQL
Having SELECT privilege is enough to kill MySQL!
(or any RDBMS)
Method 2:
START TRANSACTION;
SELECT * FROM `order` WHERE id = 24 FOR UPDATE;
SELECT SLEEP(3600 * 12);
49. More info on transactions cost
For more info on how transactions work under the hood
and why they can be expensive, ask Google for:
Jeremy Cole "The basics of the InnoDB undo logging
and history system"