What am I doing wrong here? I will post the table structure and indexes first, then the query that is slow, and many others that are very fast (instant).
How to optimize that one query to run faster ?
I know I must have added too many individual indexes, should I group them in this case ? If so, how ?
The table has 40 million records, a bit hard/slow to experiment with different index settings without knowing what I am doing.
Table and indexes:
DESCRIBE domains;
+------------------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------------------+--------------+------+-----+---------+-------+
| domain_name | varchar(128) | NO | PRI | | |
| domain_premium_extension | tinyint(1) | YES | MUL | NULL | |
| domain_contains_letters | tinyint(1) | NO | MUL | 0 | |
| domain_contains_numbers | tinyint(1) | NO | | 0 | |
| domain_contains_dashes | tinyint(1) | NO | | 0 | |
| domain_chars | tinyint(1) | NO | MUL | 0 | |
| domain_rank | mediumint(9) | NO | MUL | NULL | |
| domain_rank_delta | mediumint(9) | NO | | 0 | |
| domain_rank_date | int(11) | NO | MUL | NULL | |
| domain_best_rank | mediumint(9) | NO | | NULL | |
| domain_worst_rank | mediumint(9) | NO | | NULL | |
| domain_whois_status | varchar(32) | YES | | NULL | |
| domain_whois_email | varchar(128) | YES | | NULL | |
| domain_whois_expiration_date | int(11) | NO | MUL | NULL | |
| domain_whois_date | int(11) | NO | MUL | NULL | |
| domain_ip_date | int(11) | NO | MUL | NULL | |
| domain_availability | tinyint(1) | YES | | NULL | |
| domain_availability_date | int(11) | NO | MUL | NULL | |
| domain_virustotal_date | bigint(20) | NO | MUL | 0 | |
| domain_misc | tinyint(4) | YES | MUL | NULL | |
+------------------------------+--------------+------+-----+---------+-------+
20 rows in set (0.000 sec)
SHOW index from domains;
+---------+------------+------------------------------+--------------+------------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+------------------------------+--------------+------------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| domains | 0 | PRIMARY | 1 | domain_name | A | 43440162 | NULL | NULL | | BTREE | | |
| domains | 1 | domain_rank_date | 1 | domain_rank_date | A | 10860040 | NULL | NULL | | BTREE | | |
| domains | 1 | domain_rank | 1 | domain_rank | A | 2068579 | NULL | NULL | | BTREE | | |
| domains | 1 | domain_whois_date | 1 | domain_whois_date | A | 21720081 | NULL | NULL | | BTREE | | |
| domains | 1 | domain_whois_expiration_date | 1 | domain_whois_expiration_date | A | 21720081 | NULL | NULL | | BTREE | | |
| domains | 1 | domain_ip_date | 1 | domain_ip_date | A | 43440162 | NULL | NULL | | BTREE | | |
| domains | 1 | domain_availability_date | 1 | domain_availability_date | A | 3949105 | NULL | NULL | | BTREE | | |
| domains | 1 | domain_virustotal_date | 1 | domain_virustotal_date | A | 43440162 | NULL | NULL | | BTREE | | |
| domains | 1 | domain_misc | 1 | domain_misc | A | 2 | NULL | NULL | YES | BTREE | | |
| domains | 1 | domain_contains_letters | 1 | domain_contains_letters | A | 2 | NULL | NULL | | BTREE | | |
| domains | 1 | domain_contains_letters | 2 | domain_contains_numbers | A | 1038 | NULL | NULL | | BTREE | | |
| domains | 1 | domain_contains_letters | 3 | domain_contains_dashes | A | 3114 | NULL | NULL | | BTREE | | |
| domains | 1 | domain_premium_extension | 1 | domain_premium_extension | A | 1092 | NULL | NULL | YES | BTREE | | |
| domains | 1 | domain_chars | 1 | domain_chars | A | 23621 | NULL | NULL | | BTREE | | |
+---------+------------+------------------------------+--------------+------------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
This is the query that runs too slow, over a minute to run:
EXPLAIN SELECT * FROM domains WHERE domain_chars <= 4 AND domain_whois_expiration_date < 1689903739 AND domain_premium_extension = 1 ORDER BY domain_availability_date ASC LIMIT 50;
+------+-------------+---------+-------+--------------------------------------------------------------------+--------------------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+-------+--------------------------------------------------------------------+--------------------------+---------+------+------+-------------+
| 1 | SIMPLE | domains | index | domain_whois_expiration_date,domain_premium_extension,domain_chars | domain_availability_date | 4 | NULL | 100 | Using where |
+------+-------------+---------+-------+--------------------------------------------------------------------+--------------------------+---------+------+------+-------------+
All these below queries run instantly:
EXPLAIN SELECT * FROM domains ORDER BY domain_availability_date ASC LIMIT 50;
+------+-------------+---------+-------+---------------+--------------------------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+-------+---------------+--------------------------+---------+------+------+-------+
| 1 | SIMPLE | domains | index | NULL | domain_availability_date | 4 | NULL | 50 | |
+------+-------------+---------+-------+---------------+--------------------------+---------+------+------+-------+
EXPLAIN SELECT * FROM domains WHERE domain_chars <= 4 ORDER BY domain_availability_date ASC LIMIT 50;
+------+-------------+---------+-------+---------------+--------------------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+-------+---------------+--------------------------+---------+------+------+-------------+
| 1 | SIMPLE | domains | index | domain_chars | domain_availability_date | 4 | NULL | 567 | Using where |
+------+-------------+---------+-------+---------------+--------------------------+---------+------+------+-------------+
EXPLAIN SELECT * FROM domains WHERE domain_chars <= 4 AND domain_whois_expiration_date < 1689903739 ORDER BY domain_availability_date ASC LIMIT 50;
+------+-------------+---------+-------+-------------------------------------------+--------------------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+-------+-------------------------------------------+--------------------------+---------+------+------+-------------+
| 1 | SIMPLE | domains | index | domain_whois_expiration_date,domain_chars | domain_availability_date | 4 | NULL | 567 | Using where |
+------+-------------+---------+-------+-------------------------------------------+--------------------------+---------+------+------+-------------+
EXPLAIN SELECT * FROM domains WHERE domain_premium_extension = 1 ORDER BY domain_availability_date ASC LIMIT 50;
+------+-------------+---------+-------+--------------------------+--------------------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+-------+--------------------------+--------------------------+---------+------+------+-------------+
| 1 | SIMPLE | domains | index | domain_premium_extension | domain_availability_date | 4 | NULL | 100 | Using where |
+------+-------------+---------+-------+--------------------------+--------------------------+---------+------+------+-------------+
EXPLAIN SELECT * FROM domains WHERE domain_chars <= 4 AND domain_whois_expiration_date < 1689903739 AND domain_premium_extension = 1 LIMIT 500;
+------+-------------+---------+------+--------------------------------------------------------------------+--------------------------+---------+-------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+------+--------------------------------------------------------------------+--------------------------+---------+-------+----------+-------------+
| 1 | SIMPLE | domains | ref | domain_whois_expiration_date,domain_premium_extension,domain_chars | domain_premium_extension | 2 | const | 21720081 | Using where |
+------+-------------+---------+------+--------------------------------------------------------------------+--------------------------+---------+-------+----------+-------------+