我有一个使用服务器端分页的简单查询。问题是WHERE子句调用昂贵的函数,函数参数是用户输入,例如。用户正在搜索的内容。
SELECT
*
FROM
( SELECT /*+ FIRST_ROWS(numberOfRows) */
query.*,
ROWNUM rn FROM
(SELECT
myColumns
FROM
myTable
WHERE expensiveFunction(:userInput)=1
ORDER BY id ASC
) query
)
WHERE rn >= :startIndex
AND ROWNUM <= :numberOfRows
这很有效,并且假设numberOfRows很小。但是,我还想拥有查询的总行数。根据用户输入和数据库大小,查询最多可能需要几分钟。我目前的方法是缓存此值,但这仍然意味着用户需要等待几分钟才能看到第一个结果。
结果应该显示在Jquery datatables插件中,这对于serer端分页这样的事情有很大帮助。但是,它要求服务器返回总记录的值,以正确显示分页控件。
最好的方法是什么? (注:PHP)
我想如果立即返回第一页假冒(估计会更好)行数。加载页面后,执行ajax调用方法,该方法确定查询的总行数(如果用户在该时间内页面会发生什么情况?),然后更新伪造/估计的总行数。
但是我不知道怎么做估计。我尝试使用SAMPLE(0.1)计数(*)* 1000,但无论出于何种原因实际上需要比完整计数查询更长的时间。同样只返回假/随机值似乎也有点hacky。它需要大于1页大小才能启用“下一步”按钮。
其他想法?
答案 0 :(得分:1)
正如我在评论中所说,使用“无数”方法的一种方法。修改客户端脚本的方式是始终启用Next
按钮并获取行,直到没有,然后禁用Next
按钮。您可以随时添加一条通知消息,表示没有更多行,因此它将更加用户友好。
考虑到您期待大量记录,我怀疑用户会对所有结果进行分页。
另一种方法是安排一个cron作业,该作业将在后台对记录进行计数,并将结果存储在名为totals
的表中。应根据插入/删除的频率设置作业的运行间隔。
然后在前端,只使用先前存储在totals
中的计数。它应该对数量进行适当的近似。
答案 1 :(得分:0)
取决于您的数据库引擎。 在mysql中,解决方案如下所示:
mysql> SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name
-> WHERE id > 100 LIMIT 10;
mysql> SELECT FOUND_ROWS();
基本上,你在select(SQL_CALC_FOUND_ROWS)上添加另一个属性,它告诉mysql在执行查询的同时计算行,就好像limit子句不存在一样,而FOUND_ROWS实际上检索了那个数字。
对于oracle,请参阅此文章: How can I perform this query in oracle
其他DBMS可能有类似的东西,但我不知道。