If going to some very end of the pages, it will still fully scan all the previous records (on Disk).
One of the solution is to get the ID of the last previous record and then use where to filter (where id > previous ID Limit 0, 20 ). But if the SQL is including group up and sum, this method will not be work as the number of sum will be wrong.
Does anyone have any solution?
I know that if you want better performance, you won't use mysql. But I still like to know is there a method to optimize it.
For Example:
SELECT
productID,
locationID,
SUM(qty) AS total_qty
FROM
inventory
WHERE
create_date BETWEEN 'yyyy-mm-dd' AND 'yyyy-mm-dd'
GROUP BY
productID,
locationID
ORDER BY
productID,
locationID;
limit 100, 20;
Assuming the inventory log table has the following sample data:
id productID locationID qty create_date
1 101 1 10 2024-01-01 10:00:00
2 101 1 -2 2024-01-02 12:00:00
3 102 1 5 2024-01-03 14:00:00
4 101 2 20 2024-01-01 09:00:00
5 101 1 3 2024-01-04 16:00:00
6 102 1 -1 2024-01-05 18:00:00
With the given sql, the result will be:
SELECT
productID,
locationID,
SUM(qty) AS total_qty
FROM
inventory
WHERE
create_date BETWEEN '2024-01-01' AND '2024-01-04'
GROUP BY
productID,
locationID
ORDER BY
productID,
locationID;
Result:
productID locationID total_qty
101 1 11
101 2 20
102 1 5
But there will not only 3 records, so I would like to do pagination with limit. But I found that with (limit), it will still scan the all records before the offset on the disk. And it seem not possible to filter by keyset pagination as the id is not sequential and related.
limit 100, 20may be (P29 ,L3), (P30,L1). Then, in the next pass withlimit 120, 20the first lines may be (P30,L3), (P30,L1), (P31,L2), and you'll have got (P30,L1) twice with (P30,L2) missing from your result, because you can get the P30 rows in any order, one time as L1, L2, L3, one time as L3, L1, L2 or whatever other order - it is undefined.MIN(create_date)orMAX(create_date)to make this a valid aggregation. This indicates that you are working in MySQL's notorious cheat mode, which even was the default in old versions. In MySQL, always work insql_mode = 'ONLY_FULL_GROUP_BY'in order to be warned of invalid group-by queries rather than getting arbitrary results. And maybe you want to upgrade your version where this mode is the default.