[英]Pagination Offset Issues - MySQL
I have an orders grid holding 1 million records.我有一个包含 100 万条记录的订单网格。 The page has pagination, sort and search options.该页面具有分页、排序和搜索选项。 So If the sort order is set by customer name with a search key and the page number is 1, it is working fine.因此,如果排序顺序是由带有搜索键的客户名称设置的,并且页码为 1,则它工作正常。
SELECT * FROM orders WHERE customer_name like '%Henry%' ORDER BY
customer_name desc limit 10 offset 0
It becomes a problem when the User clicks on the last page.当用户单击最后一页时,它会成为一个问题。
SELECT * FROM orders WHERE customer_name like '%Henry%' ORDER BY
customer_name desc limit 10 offset 100000
The above query takes forever to load.上面的查询需要永远加载。 Index is set to the order id, customer name, date of order column.索引设置为订单id、客户名称、订单日期列。
I can use this solution https://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ if I don't have a non-primary key sort option, but in my case sorting is user selected.如果我没有非主键排序选项,我可以使用此解决方案https://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ ,但是在我的情况下,排序是用户选择的。 It will change from Order id, customer name, date of order etc.它将从订单 ID、客户名称、订单日期等更改。
Any help would be appreciated.任何帮助,将不胜感激。 Thanks.谢谢。
Problem 1:问题1:
LIKE "%..."
-- The leading wildcard requires a full scan of the data, or at least until it finds the 100000+10 rows. LIKE "%..."
-- 前导通配符需要对数据进行全面扫描,或者至少直到它找到 100000+10 行。 Even甚至
... WHERE ... LIKE '%qzx%' ... LIMIT 10
is problematic, since there probably not 10 such names.是有问题的,因为可能没有 10 个这样的名字。 So, a full scan of your million names.所以,全面扫描你的百万个名字。
... WHERE name LIKE 'James%' ...
will at least start in the middle of the table-- if there is an index starting with name
.将至少从表的中间开始——如果有一个以name
开头的索引。 But still, the LIMIT
and OFFSET
might conspire to require reading the rest of the table.但是, LIMIT
和OFFSET
可能会合谋要求读取表格的 rest。
Problem 2: (before you edited your Question!)问题 2:(在您编辑问题之前!)
If you leave out the WHERE
, do you really expect the user to page through a million names looking for something?如果你省略WHERE
,你真的希望用户翻阅一百万个名字来寻找东西吗?
This is a UI problem.这是一个用户界面问题。
If you have a million rows, and the output is ordered by Customer_name, that makes it easy to see the Aarons and the Zywickis, but not anyone else.如果您有一百万行,并且 output 是按 Customer_name 排序的,那么很容易看到 Aarons 和 Zywickis,但看不到其他任何人。 How would you get to me (James)?你会怎么找到我(詹姆斯)? Either you have 100K links and I am somewhere near the middle, or the poor user would have to press [Next] 'forever'.要么你有 100K 链接,而我在中间的某个地方,要么可怜的用户将不得不按 [Next] 'forever'。
My point is that the database is not the place to introduce efficiency.我的观点是,数据库不是引入效率的地方。
In some other situations, it is meaningful to go to the [Next] (or [Prev]) page.在其他一些情况下,go 到[Next](或[Prev])页面是有意义的。 In these situations, "remember where you left off", then use that to efficiently reach into the table.在这些情况下,“记住你离开的地方”,然后用它来有效地进入桌子。 OFFSET
is not efficient. OFFSET
效率不高。 More on Pagination更多关于分页
I use a special concept for this.我为此使用了一个特殊的概念。 First I have a table called pager
.首先,我有一个名为pager
的表。 It contains an primary pager_id, and some values to identify a user (user_id,session_id), so that the pager data can't be stolen.它包含一个主要的pager_id,以及一些用于标识用户的值(user_id,session_id),这样pager 数据就不会被窃取。
Then I have a second table called pager_filter
.然后我有第二个名为pager_filter
的表。 I consist of 3 ids:我由 3 个 id 组成:
pager_id int unsigned not NULL # id of table pager
order_id int unsigned not NULL # store the order here
reference_id int unsigned not NULL # reference into the data table
primary key(pager_id,order_id);
As first operation I select all records matching the filter rules from and insert them into pager_filter
作为第一个操作,我 select 匹配过滤器规则的所有记录,并将它们插入到pager_filter
DELETE FROM pager_filter WHERE pager_id = $PAGER_ID;
INSERT INTO pager_filter (pager_id,order_id,reference_id)
SELECT $PAGER_ID pager_id, ROW_NUMBER() order_id, data_id reference_id
FROM data_table
WHERE $CONDITIONS
ORDER BY $ORDERING
After filling the filter table you can use an inner join for pagination:填充过滤表后,您可以使用内部联接进行分页:
SELECT d.*
FROM pager_filter f
INNER JOIN data_table d ON d.data_id = f.reference id
WHERE f.pager_id = $PAGER_ID && f.order_id between 100000 and 100099
ORDER BY f.order_id
or或者
SELECT d.*
FROM pager_filter f
INNER JOIN data_table d ON d.data_id = f.reference id
WHERE f.pager_id = $PAGER_ID
ORDER BY f.order_id
LIMIT 100 OFFSET 100000
Hint: All code above is not tested pseudo code提示:以上所有代码都不是经过测试的伪代码
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.