MySQL 偏移无限行
Posted
技术标签:
【中文标题】MySQL 偏移无限行【英文标题】:MySQL offset infinite rows 【发布时间】:2010-09-20 07:25:45 【问题描述】:我想构造一个查询,在表中显示所有结果,但从表的开头偏移 5。据我所知,mysql 的LIMIT
需要一个限制和一个偏移量。有没有办法做到这一点?
【问题讨论】:
这是一个完全有效的问题,但我想知道以编程方式获取所有内容并忽略前几条记录是否会更好。鉴于似乎是最佳答案的恐惧(限制 5,18446744073709551615),我非常倾向于解决 MySQL 的限制。 @cesoid 如果你想要limit 5000, 18446744073709551615
怎么办。您不会为了让代码看起来漂亮而额外获取 5000 行。
@user3576887 我认为你是对的,我只是在假设 5 是唯一要求的情况下考虑上面的问题,而不是一些可能更大的不同数量(而不是解决某人其他的问题)。
我建议这是一个难得的任务,解决方案的丑陋可以接受。
【参考方案1】:
我在练习LC#1321 时遇到了一个非常相似的问题,我必须选择所有日期,但前 6 个日期被跳过。
我在 MySQL 中借助 ROW_NUMBER()
窗口函数和子查询实现了这一点。例如,以下查询返回跳过前五行的所有结果:
SELECT
fieldname1,
fieldname2
FROM(
SELECT
*,
ROW_NUMBER() OVER() row_num
FROM
mytable
) tmp
WHERE
row_num > 5;
您可能需要在子查询中添加更多逻辑,尤其是在OVER()
中以满足您的需要。此外,RANK()
/DENSE_RANK()
窗口函数可以用来代替ROW_NUMBER()
,具体取决于您的实际偏移逻辑。
参考:
MySQL 8.0 Reference Manual - ROW_NUMBER()
【讨论】:
【参考方案2】:正如其他人提到的,来自 MySQL 手册。为了实现这一点,您可以使用无符号大整数的最大值,即这个可怕的数字(18446744073709551615)。但是为了让它不那么混乱,你可以使用波浪号“~”位运算符。
LIMIT 95, ~0
它作为按位否定工作。 “~0”的结果是18446744073709551615。
【讨论】:
在 MariaDB 10.3 中不起作用 :( 我尝试了LIMIT 5, ~0
和 LIMIT ~0 OFFSET 5
。这是 MySQL 8.0 的功能吗?
这不是 MySQL 5.7 中的问题 - 语法无效。【参考方案3】:
正如其他答案中所述,MySQL 建议使用 18446744073709551615 作为限制中的记录数,但请考虑一下:如果返回 18,446,744,073,709,551,615 条记录,您会怎么做?事实上,如果你有 1,000,000,000 条记录,你会怎么做?
也许您确实想要超过 10 亿条记录,但我的意思是您想要的数量有一些限制,它小于 18 quintillion。为了稳定性、优化和可能的可用性,我建议对查询进行一些有意义的限制。这也将减少任何从未见过这个神奇数字的人的困惑,并有额外的好处,即至少传达您愿意一次处理多少条记录。
如果您真的必须从数据库中获取所有 18 个 quintillion 记录,那么您真正想要的可能是以 1 亿为增量获取它们并循环 1840 亿次。
【讨论】:
你是对的,但是把这个决定留给开发者并不是一个好的选择 @amd 你能再解释一下吗?我不知道你想说什么。 @cesoid 我认为他的意思是开发人员不应该任意选择业务逻辑,我同意这一点,但只是在一定程度上。假设您要向客户返回一个订单列表。一次返回不超过一百万是完全合理的,但限制为 100 可能会导致混乱。 @amd 我并不是说开发人员应该改变应用程序的行为以避免使用 18446744073709551615。我是说他们应该考虑使用该数字作为实现客户或界面设计师所要求的任何东西,并且它不太可能成为任何事情的正确实现。使用 MySQL 的决定可能已经由开发人员做出,而无需询问是否会有超过 18 quintillion 的东西。【参考方案4】:您可以使用带有 LIMIT 的 MySQL 语句:
START TRANSACTION;
SET @my_offset = 5;
SET @rows = (SELECT COUNT(*) FROM my_table);
PREPARE statement FROM 'SELECT * FROM my_table LIMIT ? OFFSET ?';
EXECUTE statement USING @rows, @my_offset;
COMMIT;
在 MySQL 5.5.44 中测试。因此,我们可以避免插入数字 18446744073709551615。
注意:事务确保变量@rows 与执行语句时考虑的表一致。
【讨论】:
正如@amd 所说:“在有 7M 记录的表上选择 count(*) 大约需要 17 秒”【参考方案5】:WHERE .... AND id > <YOUROFFSET>
id 可以是您拥有的任何自动递增或唯一的数字列...
【讨论】:
坏主意。如果您曾经删除过一行,它将给出不正确的偏移量。【参考方案6】:我知道这是旧的,但我没有看到类似的响应,所以这是我将使用的解决方案。
首先,我将对表执行计数查询以查看存在多少条记录。此查询速度很快,通常执行时间可以忽略不计。比如:
SELECT COUNT(*) FROM table_name;
然后我将使用从 count 获得的结果作为我的限制来构建我的查询(因为这是表可能返回的最大行数)。比如:
SELECT * FROM table_name LIMIT count_result OFFSET desired_offset;
或者可能是这样的:
SELECT * FROM table_name LIMIT desired_offset, count_result;
当然,如有必要,您可以从 count_result 中减去 desired_offset 以获得一个实际的、准确的值作为限制。如果我实际上可以确定要提供的适当限制,则传递“18446744073709551610”值是没有意义的。
【讨论】:
在有 7M 条记录的表上选择 count(*) 大约需要 17 秒【参考方案7】:来自MySQL Manual on LIMIT:
从某个特定位置检索所有行 偏移到结果的末尾 设置,你可以使用一些大的数字 第二个参数。这个说法 从第 96 行检索所有行 到最后:
SELECT * FROM tbl LIMIT 95, 18446744073709551615;
【讨论】:
太糟糕了!我来到这里是希望 MySQL 将 Limit 子句设为可选,但也提供了偏移量……但没有!我已经看到这个 18446744073709551615 散布在代码中,我在责备懒惰的程序员,但这是一个设计功能! 18446744073709551615 对于那些想知道的人来说是 2^64-1。您可能需要注意,因为您无法将此值存储在 32 位整数中。您必须确保将其存储为字符串以确保兼容性。 太糟糕了!他们需要变得更优雅...Limit -1
或Limit Null
看起来很合理!或至少 Limit 应该接受像 select * from table limit (select count(*) from table)
这样的子查询
使用 php 'PHP_INT_MAX' 避免溢出效应。
我认为这属于我刚刚编造的 TODINAWYW 的范畴,它代表 The Official Documentation is Not Always What You Want。它解释了如果您的表在(大约) 18 quintillion 行时最大化,您将如何获取所有记录,并且还建议使用“一些大数字”作为替代方案,但我建议有一个有意义的、非您愿意取回的无限且非 18-quintillion 的记录数,您应该使用它。 (我在自己的答案中包含了这个。)【参考方案8】:
就在今天,我正在阅读有关从 mysql 表中获取大量数据(超过一百万行)的最佳方法。如建议的那样,一种方法是使用LIMIT x,y
,其中x
是偏移量,y
要返回的最后一行。但是,正如我发现的那样,这并不是最有效的方法。如果您有一个自动增量列,您可以轻松地使用带有 WHERE
子句的 SELECT
语句来说明您想从哪条记录开始。
例如,
SELECT * FROM table_name WHERE id > x;
当你使用LIMIT
时,mysql 似乎得到了所有结果,然后只显示适合偏移量的记录:不是最好的性能。
来源:回答这个问题MySQL Forums。请注意,这个问题大约有 6 年的历史。
【讨论】:
如果您曾经删除过记录,这将给出不正确的结果。这种方法特别危险,因为它在大多数情况下都有效,而在无效时会静默失败。【参考方案9】:另一种方法是选择一个自动递增的列,然后使用 HAVING 对其进行过滤。
SET @a := 0;
select @a:=@a + 1 AS counter, table.* FROM table
HAVING counter > 4
但我可能会坚持使用上限方法。
【讨论】:
谢谢,我想知道如何在 PHP 语句中输入这样的查询!我的意思是这样$sql = 'SET @a :=0 SELECT .....';
【参考方案10】:
正如您提到的,LIMIT 是必需的,因此您需要使用可能的最大限制,即 18446744073709551615(无符号 BIGINT 的最大值)
SELECT * FROM somewhere LIMIT 18446744073709551610 OFFSET 5
【讨论】:
哇,这是 MySQL 团队的官方解决方案吗? 我想知道为什么有 PostgreSQL 的时候人们仍然使用 MySQL...以上是关于MySQL 偏移无限行的主要内容,如果未能解决你的问题,请参考以下文章