MySQL bù đắp các hàng vô hạn


114

Tôi muốn tạo một truy vấn hiển thị tất cả các kết quả trong một bảng, nhưng được bù bằng 5 từ đầu bảng. Theo như tôi có thể nói, MySQL LIMITyêu cầu một giới hạn cũng như bù đắp. Có cách nào để làm điều này?


1
Đây là một câu hỏi hoàn toàn hợp lệ, nhưng tôi tự hỏi liệu điều gì sẽ tốt hơn là lấy mọi thứ và bỏ qua một vài bản ghi đầu tiên theo chương trình. Với sự kinh hoàng của những gì dường như là câu trả lời tốt nhất (giới hạn 5, 18446744073709551615), tôi rất muốn giải quyết các hạn chế của MySQL's LIMIT.
cesoid,

3
@cesoid cái gì nếu bạn muốn limit 5000, 18446744073709551615. Bạn sẽ không tìm nạp thêm 5000 hàng chỉ để mã của bạn trông đẹp mắt.
elipoultorak

@ user3576887 Tôi nghĩ bạn nói đúng, tôi chỉ đang xem xét câu hỏi ở trên với giả định rằng 5 là yêu cầu duy nhất, thay vì một số khác nhau có thể lớn hơn nhiều (và thay vì giải quyết vấn đề của người khác).
cesoid

Tôi đề nghị rằng đây là một nhiệm vụ hiếm hoi đến mức có thể chấp nhận được sự xấu xí của giải pháp.
Rick James

Câu trả lời:


151

Từ Hướng dẫn sử dụng MySQL trên LIMIT :

Để truy xuất tất cả các hàng từ một khoảng chênh lệch nhất định cho đến cuối tập kết quả, bạn có thể sử dụng một số lớn nào đó cho tham số thứ hai. Câu lệnh này truy xuất tất cả các hàng từ hàng thứ 96 đến hàng cuối cùng:

SELECT * FROM tbl LIMIT 95, 18446744073709551615;

105
Kinh khủng! Tôi đến đây với hy vọng rằng MySQL đã làm cho mệnh đề Giới hạn là tùy chọn, như nó vốn có, nhưng cũng với một phần bù được cung cấp ... nhưng không! Tôi đã thấy 18446744073709551615 này rải rác trên toàn bộ mã và tôi đã đổ lỗi cho các lập trình viên lười biếng, nhưng đó là một tính năng thiết kế!
Petruza

8
câu trả lời đầy đủ, nhưng đó là chính thức từ MySQL Doc. Tôi có thể nói gì @ _ @
GusDeCooL

21
18446744073709551615 là 2 ^ 64-1 cho những ai đang thắc mắc. Bạn có thể muốn chú ý vì bạn sẽ không thể lưu trữ giá trị này ở dạng số nguyên 32 bit. Bạn phải chắc chắn rằng bạn lưu trữ nó dưới dạng một chuỗi để đảm bảo tính tương thích.
AlicanC

13
Khủng khiếp! họ cần phải trang nhã hơn thế ... Limit -1hoặc Limit Nulltrông khá hợp lý! hoặc ít nhất Giới hạn nên chấp nhận một subquery nhưselect * from table limit (select count(*) from table)
quạ vulcan

19
sử dụng php 'PHP_INT_MAX' để tránh hiệu ứng tràn.
Karl Adler

24

Như bạn đã đề cập, LIMIT là bắt buộc, vì vậy bạn cần sử dụng giới hạn lớn nhất có thể, là 18446744073709551615 (tối đa là BIGINT chưa được ký)

SELECT * FROM somewhere LIMIT 18446744073709551610 OFFSET 5

33
Chà, đây có phải là giải pháp chính thức từ nhóm MySQL không?
Antony

12

Như đã lưu ý trong các câu trả lời khác, MySQL đề xuất sử dụng 18446744073709551615 làm số lượng bản ghi trong giới hạn, nhưng hãy xem xét điều này: Bạn sẽ làm gì nếu bạn nhận lại 18,446,744,073,709,551,615 bản ghi? Trên thực tế, bạn sẽ làm gì nếu bạn có 1.000.000.000 bản ghi?

Có thể bạn muốn nhiều hơn một tỷ bản ghi, nhưng quan điểm của tôi là có một số giới hạn về số lượng bạn muốn , và nó dưới 18 nghìn tỷ. Vì lợi ích của sự ổn định, tối ưu hóa và có thể là khả năng sử dụng, tôi khuyên bạn nên đặt một số giới hạn có ý nghĩa cho truy vấn. Điều này cũng sẽ giảm bớt sự nhầm lẫn cho những ai chưa bao giờ nhìn thấy con số kỳ diệu đó và có thêm lợi ích của việc truyền đạt ít nhất bao nhiêu bản ghi mà bạn sẵn sàng xử lý cùng một lúc.

Nếu bạn thực sự phải lấy tất cả 18 nghìn tỷ bản ghi từ cơ sở dữ liệu của mình, có thể điều bạn thực sự muốn là lấy chúng theo từng bước 100 triệu và lặp lại 184 tỷ lần.


Bạn là đúng, nhưng vẫn giữ quyết định này để các nhà phát triển không phải là một lựa chọn tốt
AMD

@amd Bạn có thể giải thích thêm một chút không? Tôi không biết bạn đang muốn nói gì.
cesoid

1
@cesoid Tôi nghĩ anh ấy đang nói rằng các nhà phát triển không nên là người tự ý chọn logic kinh doanh, điều mà tôi đồng ý, nhưng chỉ ở một điểm nào đó. Giả sử bạn đang trả lại danh sách đơn đặt hàng cho khách hàng. Hoàn toàn hợp lý để không bao giờ trả lại nhiều hơn một triệu mỗi lần, nhưng giới hạn ở mức 100 có thể gây nhầm lẫn.
Mùa thu Leonard

@amd Tôi không nói rằng nhà phát triển nên thay đổi hành vi của ứng dụng để tránh sử dụng 18446744073709551615. Tôi nói rằng họ nên cân nhắc xem việc sử dụng số đó có hợp lý hay không trong quá trình triển khai bất kỳ ứng dụng khách hoặc nhà thiết kế giao diện nào đã yêu cầu, và nó rất khó có khả năng triển khai đúng cho bất kỳ điều gì. Quyết định sử dụng MySQL có lẽ đã được nhà phát triển đưa ra mà không cần hỏi liệu sẽ có hơn 18 nghìn tỷ thứ gì đó hay không.
cesoid

5

Một cách tiếp cận khác sẽ là chọn một cột tự động tạo và sau đó lọc nó bằng cách sử dụng HAVING.

SET @a := 0; 
select @a:=@a + 1 AS counter, table.* FROM table 
HAVING counter > 4

Nhưng tôi có thể sẽ gắn bó với cách tiếp cận giới hạn cao.


cảm ơn bạn, và tôi tự hỏi làm thế nào tôi có thể đặt truy vấn như vậy trong câu lệnh PHP! tôi có nghĩa là giống như cách mà$sql = 'SET @a :=0 SELECT .....';
Reham Fahmy

2

Như những người khác đã đề cập, từ hướng dẫn sử dụng MySQL. Để đạt được điều đó, bạn có thể sử dụng giá trị tối đa của một số nguyên lớn không dấu, đó là số khủng khiếp này (18446744073709551615). Nhưng để làm cho nó bớt lộn xộn hơn một chút, bạn có thể sử dụng toán tử bitwise "~" dấu ngã.

  LIMIT 95, ~0

nó hoạt động như một phủ định bit. Kết quả của "~ 0" là 18446744073709551615.


1
Không làm việc trong MariaDB 10,3 :( Tôi đã thử cả hai LIMIT 5, ~0LIMIT ~0 OFFSET 5Đây có phải là một tính năng MySQL 8.0.?
jurchiks

1
Đây không phải là một điều trong MySQL 5.7 - cú pháp không hợp lệ.
Jonny Nott

0

Mới hôm nay, tôi đã đọc về cách tốt nhất để lấy lượng dữ liệu khổng lồ (hơn một triệu hàng) từ bảng mysql. Một cách là, như đã đề xuất, sử dụng LIMIT x,yđâu xlà độ lệch và yhàng cuối cùng bạn muốn trả về. Tuy nhiên, như tôi phát hiện ra, đó không phải là cách hiệu quả nhất để làm như vậy. Nếu bạn có cột tự động tăng, bạn có thể dễ dàng sử dụng một SELECTcâu lệnh có WHEREmệnh đề cho biết bạn muốn bắt đầu bản ghi nào.

Ví dụ, SELECT * FROM table_name WHERE id > x;

Có vẻ như mysql nhận được tất cả các kết quả khi bạn sử dụng LIMITvà sau đó chỉ hiển thị cho bạn các bản ghi phù hợp với phần bù: không phải là tốt nhất cho hiệu suất.

Nguồn: Câu trả lời cho câu hỏi này Diễn đàn MySQL . Chỉ cần lưu ý, câu hỏi là khoảng 6 năm tuổi.


13
Điều này sẽ cho kết quả không chính xác nếu bạn đã từng xóa bản ghi. Phương pháp này đặc biệt nguy hiểm, vì nó hoạt động hầu hết thời gian và thất bại âm thầm khi nó không hoạt động.
Octern

0

Bạn có thể sử dụng một câu lệnh MySQL với LIMIT:

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;

Đã thử nghiệm trong MySQL 5.5.44. Như vậy, chúng ta có thể tránh được việc chèn số 18446744073709551615.

lưu ý: giao dịch đảm bảo rằng biến @rows phù hợp với bảng được xem xét khi thực hiện câu lệnh.


như @amd đã nêu: "số lượng chọn (*) trên bảng có 7 triệu bản ghi mất khoảng 17
giây

-1

Tôi biết rằng điều này đã cũ nhưng tôi không thấy phản hồi tương tự vì vậy đây là giải pháp tôi sẽ sử dụng.

Đầu tiên, tôi sẽ thực hiện một truy vấn đếm trên bảng để xem có bao nhiêu bản ghi tồn tại. Truy vấn này nhanh và thông thường thời gian thực hiện không đáng kể. Cái gì đó như:

SELECT COUNT(*) FROM table_name;

Sau đó, tôi sẽ xây dựng truy vấn của mình bằng cách sử dụng kết quả tôi nhận được từ tính là giới hạn của mình (vì đó là số hàng tối đa mà bảng có thể trả về). Cái gì đó như:

SELECT * FROM table_name LIMIT count_result OFFSET desired_offset;

Hoặc có thể là một cái gì đó như:

SELECT * FROM table_name LIMIT desired_offset, count_result;

Tất nhiên, nếu cần, bạn có thể lấy count_result trừ hệ số mong muốn để lấy giá trị thực tế, chính xác để cung cấp làm giới hạn. Việc chuyển giá trị "18446744073709551610" không có ý nghĩa gì nếu tôi thực sự có thể xác định giới hạn thích hợp để cung cấp.


2
chọn count (*) trên một bảng với hồ sơ 7M mất khoảng 17s
AMD

-7
WHERE .... AND id > <YOUROFFSET>

id có thể là bất kỳ cột số tự động tăng hoặc duy nhất nào mà bạn có ...


7
Ý kiến ​​tồi. Nó sẽ cung cấp độ lệch không chính xác nếu bạn đã từng xóa một hàng.
Octern
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.