I'm having a problem with SQL and slow response times.
It's not because I'm missing indexes but, because the results are HUGE. I'm using these to feed an API response where this is delivered to an external client. To make the responses manageable, I'm using pagination. Eventually large pages eventually slow down to the point where it takes 800 seconds to complete. That means the web service is hanging around for that long waiting to deliver the response.
mysql> EXPLAIN SELECT * FROM externallinks_global LEFT JOIN externallinks_paywall ON externallinks_global.paywall_id=externallinks_paywall.paywall_id WHERE `has_archive` = 1 LIMIT 1385000,1001;
+------+-------------+-----------------------+--------+------------------------------------------------------------------+------------+---------+--------------------------------------------------+---------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-----------------------+--------+------------------------------------------------------------------+------------+---------+--------------------------------------------------+---------+-------+
| 1 | SIMPLE | externallinks_global | ref | HASARCHIVE,APIINDEX7,APIINDEX10,APIINDEX11,APIINDEX12,APIINDEX13 | APIINDEX13 | 1 | const | 4291236 | |
| 1 | SIMPLE | externallinks_paywall | eq_ref | PRIMARY | PRIMARY | 4 | s51059__cyberbot.externallinks_global.paywall_id | 1 | |
+------+-------------+-----------------------+--------+------------------------------------------------------------------+------------+---------+--------------------------------------------------+---------+-------+
2 rows in set (0.01 sec)
The above is a problem query being explained. This took 800 seconds to execute. It's pretty well indexed as can be seen. My question is how can I get the results almost instantly when fetching a chunk of the result deep within the large set? Is there some way to do this?
Here is the table the query is being run on and the table joining it:
CREATE TABLE IF NOT EXISTS `externallinks_global` (
`url_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`paywall_id` INT UNSIGNED NOT NULL,
`url` VARCHAR(767) NOT NULL,
`archive_url` BLOB NULL,
`has_archive` TINYINT UNSIGNED NOT NULL DEFAULT '0',
`live_state` TINYINT UNSIGNED NOT NULL DEFAULT '4',
`last_deadCheck` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
`archivable` TINYINT UNSIGNED NOT NULL DEFAULT '1',
`archived` TINYINT UNSIGNED NOT NULL DEFAULT '2',
`archive_failure` BLOB NULL DEFAULT NULL,
`access_time` TIMESTAMP NOT NULL,
`archive_time` TIMESTAMP NULL DEFAULT NULL,
`reviewed` TINYINT UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`url_id` ASC),
UNIQUE INDEX `url_UNIQUE` (`url` ASC),
INDEX `LIVE_STATE` (`live_state` ASC),
INDEX `LAST_DEADCHECK` (`last_deadCheck` ASC),
INDEX `PAYWALLID` (`paywall_id` ASC),
INDEX `REVIEWED` (`reviewed` ASC),
INDEX `HASARCHIVE` (`has_archive` ASC),
INDEX `ISARCHIVED` (`archived` ASC),
INDEX `APIINDEX1` (`live_state` ASC, `paywall_id` ASC),
INDEX `APIINDEX2` (`live_state` ASC, `paywall_id` ASC, `archived` ASC),
INDEX `APIINDEX3` (`live_state` ASC, `paywall_id` ASC, `reviewed` ASC),
INDEX `APIINDEX4` (`live_state` ASC, `archived` ASC),
INDEX `APIINDEX5` (`live_state` ASC, `reviewed` ASC),
INDEX `APIINDEX6` (`archived` ASC, `reviewed` ASC),
INDEX `APIINDEX7` (`has_archive` ASC, `paywall_id` ASC),
INDEX `APIINDEX8` (`paywall_id` ASC, `archived` ASC),
INDEX `APIINDEX9` (`paywall_id` ASC, `reviewed` ASC),
INDEX `APIINDEX10` (`has_archive` ASC, `live_state` ASC, `paywall_id` ASC, `archived` ASC, `reviewed` ASC),
INDEX `APIINDEX11` (`has_archive` ASC, `archived` ASC, `reviewed` ASC),
INDEX `APIINDEX12` (`has_archive` ASC, `live_state` ASC, `paywall_id` ASC),
INDEX `APIINDEX13` (`has_archive` ASC, `live_state` ASC),
INDEX `APIINDEX14` (`has_archive` ASC, `live_state` ASC, `paywall_id` ASC, `reviewed` ASC),
INDEX `APIINDEX15` (`has_archive` ASC, `live_state` ASC, `reviewed` ASC),
INDEX `APIINDEX16` (`has_archive` ASC, `paywall_id` ASC, `reviewed` ASC));
and
CREATE TABLE IF NOT EXISTS `externallinks_paywall` (
`paywall_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`domain` VARCHAR(255) NOT NULL,
`paywall_status` TINYINT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (`paywall_id` ASC),
UNIQUE INDEX `domain_UNIQUE` (`domain` ASC),
INDEX `PAYWALLSTATUS` (`paywall_status` ASC));
The global table has roughly 27 million rows, and the paywall table has about 16 million.