I have a very large table of over 9 million rows and in my software I need to rapidly do select queries on it in a loop. The problem is that the queries take almost 4 seconds to complete. Here is one of the queries (they are all similar in that they all have the same WHERE clause that is slowing them down:
SELECT MIN(id)
FROM `04c1Tg0M`
WHERE `tried` = 0;
I'm using the tried column as a boolean. the value is either 1 or 0. Here is the EXPLAIN from that query:
--------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+---------------+------+---------+------+---------+--------------------------+
| 1 | SIMPLE | 04c1Tg0M | index | NULL | pdex | 158 | NULL | 9275107 | Using where; Using index |
+----+-------------+----------+-------+---------------+------+---------+------+---------+--------------------------+
Here is the table structure:
CREATE TABLE `04c1Tg0M` (
`id` int(20) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`tried` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `pdex` (`username`,`id`,`tried`)
) ENGINE=MyISAM AUTO_INCREMENT=9275108 DEFAULT CHARSET=utf8
Here is the output of show indes:
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| 04c1Tg0M | 0 | PRIMARY | 1 | id | A | 9275107 | NULL | NULL | | BTREE | |
| 04c1Tg0M | 1 | pdex | 1 | username | A | 9275107 | NULL | NULL | | BTREE | |
| 04c1Tg0M | 1 | pdex | 2 | id | A | 9275107 | NULL | NULL | | BTREE | |
| 04c1Tg0M | 1 | pdex | 3 | tried | A | 9275107 | NULL | NULL | YES | BTREE | |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
And here is the output from the query in question:
+---------+
| MIN(id) |
+---------+
| 1 |
+---------+
1 row in set (3.76 sec)
I need to drastically reduce the query time. Any help is greatly appreciated.
You should add an index on (tried, id)
.
You already added an index on (username,id,tried)
but this index cannot be used efficiently for the query you wrote because the field tried
is not the first item in the index.
From the manual page How MySQL Uses Indexes:
MySQL uses indexes for these operations:
To find the
MIN()
orMAX()
value for a specific indexed columnkey_col
. This is optimized by a preprocessor that checks whether you are usingWHERE key_part_N = constant
on all key parts that occur beforekey_col
in the index. In this case, MySQL does a single key lookup for eachMIN()
orMAX()
expression and replaces it with a constant. If all expressions are replaced with constants, the query returns at once. For example:SELECT MIN(key_part2),MAX(key_part2) FROM tbl_name WHERE key_part1=10;
Note in particular that the WHERE
clause must refer to columns that occur before the column for which you wish to calculate the MIN
or MAX
, which is why your current index is not used efficiently.
I need to rapidly do select queries on it in a loop
Are you sure that you need to query in a loop? Have you considered moving the loop into the database? Maybe what you really need is a join? It's better to send a single query that fetches a lot of data than lots of small queries that fetch only a small amount of data each.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With