Select for indexed field with >= is much faster than with = Execution time for the query

SELECT id
FROM Deals
WHERE is_demo = 0 
AND asset_id &gt;= 71 
AND exp_time &gt;= UNIX_TIMESTAMP(UTC_TIMESTAMP() - INTERVAL 30 HOUR);


is 0.5s, but if we change asset_id&gt;=71 to asset_id=71 the execution time is about 10 seconds.

Why &gt;=71 if much faster than simple equal operation =71?

Indexes for all fields are used.

CREATE TABLE `Deals`
(
    id INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
    user_id INT(11) NOT NULL,
    is_demo TINYINT(1) NOT NULL,
    asset_id INT(11) NOT NULL,
    exp_time INT(11) NOT NULL,
);
CREATE INDEX asset_idx ON `Deal` (asset_id);
CREATE INDEX exp_timex ON `Deal` (exp_time);
CREATE INDEX is_demo ON `Deal` (is_demo);
CREATE INDEX user_idx ON `Deal` (user_id);
With &gt;=, the optimizer had two indexes to choose from.  Apparently it chose (exp_time).  Please provide EXPLAIN SELECT ... to confirm this. Also run EXPLAIN FORMAT=JSON SELECT ...

With =, the optimizer still has two to choose from, but probably picked = (asset_id). But there were a lot of 71's, so it turned out to be a bad choice.

That choice can be improved by having INDEX(asset_id, exp_time) in place of simply (asset_id).  This may run faster than even 0.5s.  This 'composite' index can use both parts of the WHERE clause, thereby being more efficient.  (The &gt;= version can't use both columns of a composite index because it can't handle 2 ranges at the same time.)

And even better than  (asset_id, exp_time): (is_demo, asset_id, exp_time) or (asset_id, is_demo, exp_time).

It could be that the "statistics" are stale -- run ANALYZE TABLE Deals to see if things improve.  But don't hold your breath; this is not a panacea.