Here is a simple demonstration of the importance of keys in query performance. The example uses three tables from the Sakila database (downloadable from https://dev.mysql.com/doc/sakila/en/sakila-installation.html)--customer with a primary key and about 700 rows, and rental and payment , each with a primary key, a foreign key referencing customer , and about 16,000 rows. The query just counts joined customer, rental and payment rows:
SELECT COUNT(*) FROM customer c JOIN rental r USING (customer_id) JOIN payment p USING (customer_id);First, turn off caching so we can see the effects of indexes by themselves: set query_cache_type=0; set query_cache_size=0; reset query cache;The query with a SQL_NO_CACHE qualifier finishes in three-quarters of a second:
SELECT SQL_NO_CACHE COUNT(*) AS JoinResultRowsNoKeys FROM customer c JOIN rental r USING (customer_id) JOIN payment p USING (customer_id); +-----------------------+ | JoinResultRowsAllKeys | +-----------------------+ | 445505 | +-----------------------+ 1 row in set (0.47 sec)Here is EXPLAIN output for the query:
+----+-------------+-------+-------+--------------------+--------------------+---------+----------------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+--------------------+--------------------+---------+----------------------+------+-------------+ | 1 | SIMPLE | c | index | PRIMARY | idx_fk_store_id | 1 | NULL | 541 | Using index | | 1 | SIMPLE | r | ref | idx_fk_customer_id | idx_fk_customer_id | 2 | sakila.c.customer_id | 13 | Using index | | 1 | SIMPLE | p | ref | idx_fk_customer_id | idx_fk_customer_id | 2 | sakila.c.customer_id | 14 | Using index | +----+-------------+-------+-------+--------------------+--------------------+---------+----------------------+------+-------------+Multiplying the rowcounts for each table EXPLAIN lists gives a rough measure of how many rows the query engine will have to examine: 541*13*14, or 98,462.
Now make copies of those tables in another database, with no indexes at all, and run the same query on the new raw tables:
drop schema if exists saktest; create schema saktest; use saktest; drop table if exists customer,rental,payment; create table customer engine=innodb select * from sakila.customer; create table rental engine=innodb select * from sakila.rental; create table payment engine=innodb select * from sakila.payment; SELECT SQL_NO_CACHE COUNT(*) AS JoinResultRowsNoKeys FROM customer c JOIN rental r USING (customer_id) JOIN payment p USING (customer_id); +----------------------+ | JoinResultRowsNoKeys | +----------------------+ | 445505 | +----------------------+ 1 row in set (23.34 sec)It's almost 50 times slower. EXPLAIN shows why:
+----+-------------+-------+------+---------------+------+---------+------+-------+--------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+-------+--------------------------------+ | 1 | SIMPLE | c | ALL | NULL | NULL | NULL | NULL | 637 | | | 1 | SIMPLE | r | ALL | NULL | NULL | NULL | NULL | 16130 | Using where; Using join buffer | | 1 | SIMPLE | p | ALL | NULL | NULL | NULL | NULL | 16272 | Using where; Using join buffer | +----+-------------+-------+------+---------------+------+---------+------+-------+--------------------------------+Without indexes, it must examine 637*16130*16272=167,191,708,320 rows, more than a million-and-a-half times more row comparisons than the same query with indexes. We could take the fact that it's only 50 times slower as a tribute to the query engine. If your query is sluggish, look at the keys. Last updated 17 Apr 2024 |
![]() |