【问题标题】:SQL pagination for on-the-fly data动态数据的 SQL 分页
【发布时间】:2012-02-21 20:42:05
【问题描述】:

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

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

我的问题是:当结果在后端合并时,我是否需要创建一个带有结果的临时视图,然后供 PHP 分页使用?还是我创建一个表?我不希望每个查询都有一堆视图和/或表格。另外,如果我确实使用临时表,它们何时被销毁?如果用户点击他/她浏览器上的“返回”按钮会怎样?

我希望这是有道理的。如果您不明白,请要求澄清。我在下面提供了更多信息。

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

【问题讨论】:

标签: database pagination


【解决方案1】:

这取决于您的数据库引擎(即哪种 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 的所有内容

【讨论】:

  • 这假设我已经有一个填充了数据的表......返回给用户的结果是即时生成的,所以我觉得它是不同的。
  • 好吧,您在问题中说您从数据库生成结果。所以我假设你实际上在数据库中的某个地方有一些数据,你用 SQL 查询......对吗?
  • 是和不是。查看此图像以了解其工作原理。基本上,引擎为用户输入的每个单词获取单独的结果表,然后将表中的相应结果合并以获得最终列表,然后将其排序并返回给用户。 i.imgur.com/gLJ6s.png 。所以当我说结果在数据库中是“技术上”时,你明白我的意思了吗?
  • @Jon:我明白你的意思,但我仍然没有看到问题所在。我编辑了我的答案,见上文!
  • 你的解释让我有点困惑。所以你建议我将单个结果表(查询中的每个单词)放入一个大型临时表中?添加完成的时间和地点(我在上图中进行了说明)。这听起来很有希望,我只是想确保我明白你在说什么。另外,什么时候删除临时表?只要用户浏览分页结果,它是否需要存在?还是数据一旦到达前端就保存在内存中,因此一旦呈现给用户就可以将其删除?
【解决方案2】:

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

最好使用存储过程来完成。

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

【讨论】:

  • 临时表何时删除?只要用户浏览分页结果,它是否需要存在?还是数据一旦到达前端就保存在内存中,因此一旦呈现给用户就可以将其删除?
  • 为显示的每个页面删除并重新创建。至少我过去是这样做的。
猜你喜欢
  • 2012-11-07
  • 2014-07-21
  • 1970-01-01
  • 1970-01-01
  • 2010-09-17
  • 2017-05-30
  • 1970-01-01
  • 2021-06-04
  • 1970-01-01
相关资源
最近更新 更多