即时数据的SQL分页

时间:2012-02-21 20:42:06

标签: database pagination

我是分页的新手,所以我不确定我是否完全理解它是如何工作的。但这就是我想要做的。

基本上,我正在创建一个可以从数据库生成结果的搜索引擎( MySQL )。这些结果通过算法合并在一起,然后返回给用户。

我的问题是:当结果在后端合并时,我是否需要创建一个临时视图,其结果随后由PHP分页使用?或者我创建一个表?我不希望每个查询都有一堆视图和/或表。另外,如果我使用临时表,它们什么时候被销毁?如果用户点击他/她的浏览器上的“后退”按钮怎么办?

我希望这是有道理的。如果您不明白,请询问澄清。我在下面提供了一些信息。

更多解释:数据库包含英语单词和短语,每个单词和短语都映射到一个概念(例如:“apple”在语义上与“烹饪”的概念相关,为0.67)。用户可以输入一组关键字,并找到与这些关键字中最接近的匹配概念。因此,我在数学上将原始关系分数组合起来,以找到用户输入的单词集的最语义相关概念的排序列表。所以它并不像构建SQL查询那样简单,例如“SELECT * FROM words WHERE blah blah ...”

2 个答案:

答案 0 :(得分:2)

这取决于您的数据库引擎(即什么样的SQL),但几乎每种SQL风格都支持对查询进行分页。

例如,MySQL有LIMIT,MS SQL有ROW_NUMBER

所以你像往常一样构建你的SQL,然后你只需添加特定于数据库引擎的分页内容,服务器只会自动返回查询结果的第10行到第20行。


修改

因此,最终查询(选择返回给用户的数据)会按照我的预期从某些表(临时或非临时)中选择数据。
它是SELECT查询,您可以在MySQL中使用LIMIT进行寻呼。

您的描述对我来说听起来好像实际计算比将结果返回给用户的最终查询更耗费资源。

所以我会做以下事情:

  • 获取输入单词的各个结果表,并将其保存在表格中,以便稍后可以获取此特定查询的数据(例如,使用其他列,如SessionID或QueryID)。这里没有分页。
  • 再次查询这些结果表以查找返回给用户的最终查询 您可以在此处使用LIMIT 进行分页。

因此,当用户启动"时,您必须只进行一次实际计算(资源占用查询)。查询。然后,只需从已填充的结果表中进行选择,即可将分页结果返回给用户。


编辑2:

我刚刚看到你接受了我的答案,但是,这里还有关于我使用"临时"的详细信息。表。

当然,这只是一种可行的方法。如果预期结果不是太大,则将整个结果集返回给客户端,将其保留在内存中并执行分页客户端(如您所建议的那样)。 但是,如果我们谈论的是真正的大量数据,用户只会查看一些数据(比如Google搜索结果)和/或带宽较低,那么您只想将尽可能少的数据传输到客户端。

当我写这个答案时,我正在思考的是什么。

所以:我不是指一个真实的"临时表,我正在谈论"正常"用于保存临时数据的表 我在MS SQL方面比在MySQL方面更精通,所以我对MySQL中的临时表不太了解。
我可以告诉你我将如何在MS SQL中做到这一点,但也许在MySQL中有一个我不了解的更好的方法。

当我必须分页资源密集型查询时,我想进行一次实际计算,将其保存在表中,然后从客户端多次查询该表(以避免再次对每个表进行计算)页)。
问题是:在MS SQL中,临时表仅存在于创建它的查询范围内 所以我不能使用临时表,因为当我想第二次查询它时它会消失。

所以我使用"真实"这样的表格。
我不确定我是否理解你的算法示例是正确的,所以我稍微简化了一下这个例子。我希望无论如何我能说清楚:

这是表(这可能不是MySQL,它只是为了展示这个概念):

create table AlgorithmTempTable
(
    QueryID guid,
    Rank float,
    Value float
)

正如我之前所说 - 它并不是一个临时的"临时的"表,它实际上是一个真正的永久表,仅用于临时数据。

现在,用户打开您的应用程序,输入他的搜索词并按下"搜索"按钮。

然后启动资源丰富的算法来计算结果一次,并将其存储在表中:

insert into AlgorithmTempTable (QueryID, Rank, Value)
select '12345678-9012-3456789', foo, bar
from Whatever

insert into AlgorithmTempTable (QueryID, Rank, Value)
select '12345678-9012-3456789', foo2, bar2
from SomewhereElse

Guid必须为客户所知。也许你可以使用客户端的SessionID(如果他有一个,如果他不能一次启动多个查询......或者你每次用户按下时在客户端上生成一个新的Guid "搜索"按钮,或其他)。

现在所有的计算都已完成,排序的结果列表保存在表格中 现在您可以查询表,按QueryID过滤:

select Rank, Value
from AlgorithmTempTable
where QueryID = '12345678-9012-3456789'
order by Rank
limit 0, 10

由于QueryID,多个用户可以同时执行此操作,而不会干扰彼此的查询。如果为每个搜索创建一个新的QueryID,则同一个用户甚至可以一次运行多个查询。

现在只剩下一件事了:当不再需要的时候删除临时数据(只有数据!表永远不会掉线)。
因此,如果用户关闭查询屏幕:

delete
from AlgorithmTempTable
where QueryID = '12345678-9012-3456789'

但在某些情况下,这并不理想。如果应用程序崩溃,数据将永久保留在表中 有几种更好的方法。哪一款最适合您取决于您​​的应用。一些可能性:

  • 您可以使用当前时间作为默认值添加日期时间列,然后运行删除早于X的所有内容的夜间(或每周)作业
  • 与上述相同,但每次有人开始新查询时,您都可以删除早于X的所有内容,而不是每周作业。
  • 如果每个用户都有一个会话,则可以将SessionID保存在表格的附加列中。当用户注销或会话过期时,您可以使用表
  • 中的SessionID删除所有内容

答案 1 :(得分:0)

分页结果可能非常棘手。我这样做的方式如下。为可能运行的任何查询设置上限。例如说5,000。如果查询返回的值超过5,000,则将结果限制为5,000。

最好使用存储过程完成。

  1. 将查询结果存储到临时表中。
  2. 从临时表中选择页面X的数据量。
  3. 还返回当前页面和总页数。