简体   繁体   English

分页偏移问题 - MySQL

[英]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.但是, LIMITOFFSET可能会合谋要求读取表格的 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM