Yes, we have a multi-column index (combo1) on column (field1, field9 and field12)
Yes, returning the 1st or last 50 is instant. Its only the rows that reside in the middle. The closer you get to middle, the longer the query takes
no thanks
EXPLAIN shows a key len of 2 bytes, which is the size of field1. That means it only uses the first part of the index. If it used all three, it would use 2+1+4 = 7 bytes.
field1 * POW(2, 33) + field9 * POW(2, 32) + field12
. You'd have to query rows whose values are BETWEEN 1201 * POW(2, 33) AND 1202 * POW(2, 33) - 1
. MySQL has not always been very good with BIGINTs and ranged queries though, so I don't know how well that would work.axe70 wrote: ↑Thu Nov 05, 2020 5:02 pmI really like to work with things under my hand (since not so smart) can so you provide an sql structure dump, may saved via phpmyadmin, that would be so possible to load in seconds as test, and i'll have your same 2 or 3 tables/scenario into a database test?
also a dump containing data to load would be nice (maybe 10 or 20 records with data modified if necessary for privacy). I assume so more then one will try to test out the thing as presented, and i would be one of those probably!
Code: Select all
CREATE TABLE `testtable1` (
`item_number` int(10) unsigned NOT NULL AUTO_INCREMENT,
`field1` smallint(8) unsigned NOT NULL DEFAULT '0',
`field2` varchar(250) NOT NULL,
`field3` mediumint(8) NOT NULL DEFAULT '0',
`field4` int(11) NOT NULL DEFAULT '0',
`field5` mediumint(8) unsigned NOT NULL DEFAULT '0',
`field6` mediumint(8) unsigned NOT NULL DEFAULT '0',
`field7` tinyint(3) NOT NULL DEFAULT '0',
`field8` tinyint(1) NOT NULL DEFAULT '0',
`field9` tinyint(3) NOT NULL DEFAULT '0',
`field10` int(10) unsigned NOT NULL DEFAULT '0',
`field11` varchar(25) NOT NULL,
`field12` int(10) unsigned NOT NULL DEFAULT '0',
`field13` mediumint(8) NOT NULL DEFAULT '0',
`field14` varchar(25) NOT NULL,
`field15` int(11) NOT NULL DEFAULT '0',
`field16` int(10) unsigned NOT NULL DEFAULT '0',
`field17` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`item_number`),
KEY `field1` (`field1`),
KEY `field16` (`field16`),
KEY `field7` (`field7`),
KEY `field9` (`field9`),
KEY `field12` (`field12`),
KEY `combo1` (`field1`,`field9`,`field12`),
KEY `combo2` (`field1`,`field13`),
KEY `combo3` (`field1`,`field4`)
) ENGINE=InnoDB AUTO_INCREMENT=754588921 DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED$$
Code: Select all
INSERT INTO testtable1 (item_number, field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16, field17) VALUES
(552578116, 1201, 'This is text text for field 2. This is only a test so we can do a test of field 2. This has only been a test.', 5567864, 1604609050, 954188, 0, 0, 0, 0, 576694909, 'Test 1234', 5567864, 5567864, 'Test 1234', 1604609050, 0, 1);
Using explain without a force gives thisJoshyPHP wrote: ↑Thu Nov 05, 2020 6:07 pmEXPLAIN shows a key len of 2 bytes, which is the size of field1. That means it only uses the first part of the index. If it used all three, it would use 2+1+4 = 7 bytes.
Try ANALYZE-ing the table, maybe replace USE INDEX with FORCE INDEX too.
As a last resort, I would experiment with an indexed column solely dedicated to this type of query. Maybe a BIGINT column whose value is equal tofield1 * POW(2, 33) + field9 * POW(2, 32) + field12
. You'd have to query rows whose values areBETWEEN 1201 * POW(2, 33) AND 1202 * POW(2, 33) - 1
. MySQL has not always been very good with BIGINTs and ranged queries though, so I don't know how well that would work.
Ideally you'd replace the pagination so you don't have to order then skip thousands of records but you'd need to know the field9 and field12 values for the previous page and I don't know if it's possible in your case.