I created table categories
:
CREATE TABLE `categories` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`type` int unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `type` (`type`)
) ENGINE=InnoDB AUTO_INCREMENT=1100001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
Then I filled table with random data:
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test_perf', 'login', 'password');
$pdo->beginTransaction();
for ($i = 0; $i < 1000000; $i++) {
$pdo->exec("INSERT INTO categories (name, type) VALUES ('" . uniqid() . "', 1)");
}
$pdo->commit();
Statistics for table indexes:
mysql> SHOW INDEXES FROM categories;
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| categories | 0 | PRIMARY | 1 | id | A | 1097250 | NULL | NULL | | BTREE | | | YES | NULL |
| categories | 1 | type | 1 | type | A | 1 | NULL | NULL | | BTREE | | | YES | NULL |
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set (0,01 sec)
It`s right, index type
has only one value (1).
Then I try select by type with ignore index(type)
:
mysql> select MAX(name) FROM categories ignore index(type) WHERE type=1;
+---------------+
| MAX(name) |
+---------------+
| 6769b0dfec5e7 |
+---------------+
1 row in set (0,23 sec)
mysql> explain select MAX(name) FROM categories ignore index(type) WHERE type=1;
+----+-------------+------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| 1 | SIMPLE | categories | NULL | ALL | NULL | NULL | NULL | NULL | 1097250 | 100.00 | Using where |
+----+-------------+------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0,00 sec)
And without it:
mysql> select MAX(name) FROM categories WHERE type=1;
+---------------+
| MAX(name) |
+---------------+
| 6769b0dfec5e7 |
+---------------+
1 row in set (0,80 sec)
mysql> explain select MAX(name) FROM categories WHERE type=1;
+----+-------------+------------+------------+------+---------------+------+---------+-------+--------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+------+---------------+------+---------+-------+--------+----------+-------+
| 1 | SIMPLE | categories | NULL | ref | type | type | 4 | const | 548625 | 100.00 | NULL |
+----+-------------+------------+------------+------+---------------+------+---------+-------+--------+----------+-------+
1 row in set, 1 warning (0,00 sec)
As you can see, mysql uses index type
, but it only degrades performance. At the same time, the statistics are correct.
Why mysql uses index type
?
Mysql version: 8.0.35-0ubuntu0.22.04.1.
I expecting mysql should not use this index.
2
Answers
MySQL is using the index on the
type
column because it is optimized for filtering rows that matchWHERE type = 1
. However, in this case, the use of the index is not beneficial because the query needs to scan a large portion of rows and retrieve theMAX(name)
, which requires accessing the actual data rows rather than just the index.If you want to improve performance you can try forcing a full table scan while ignoring the index like:
Short answer for question
Why mysql uses index type?
– DBMS assume thatYour explain select … shows this.
I think for such a bad case, when there is 1 value per 1M rows, cardinality does not give a proper prediction and therefore it is simply assumed to be fifty-fifty 😉
Query model (with 100K rows) shows that it preferably performs an index scan if the cardinality of the type is >15.
Insert 100K rows.
Execute 2 queries
We can see that table scan duration is 0.04764225, index scan – 0.16639675.
Execution statistics
    -> Filter: (categories.`type` = 1) (cost=10000 rows=1) (actual time=0.0541..38.3 rows=100001 loops=1)
        -> Table scan on categories (cost=10000 rows=100001) (actual time=0.0524..30.8 rows=100001 loops=1)
For index scan expected rows=50K, fact rows=100K.
    -> Index lookup on categories using type (type=1) (cost=5001 rows=50000) (actual time=0.136..122 rows=100001 loops=1)
Exeqution time statistics
type
Cardinalityfiddle
Update1. For interest
With
create index ix_type_name on categories(type,name);
Execution time
Execution plans for both queries
fiddle