Làm thế nào để MySQL xử lý ĐẶT HÀNG BỞI và GIỚI HẠN trong một truy vấn?


251

Tôi có một truy vấn giống như thế này:

SELECT article FROM table1 ORDER BY publish_date LIMIT 20

Làm thế nào để đặt hàng theo công việc? Nó sẽ đặt hàng tất cả các hồ sơ, sau đó nhận được 20 hồ sơ đầu tiên, hoặc sẽ nhận được 20 hồ sơ và đặt hàng theo publish_datelĩnh vực?

Nếu đó là bài cuối cùng, bạn không được đảm bảo thực sự có được 20 bài viết gần đây nhất.


6
Lưu ý rằng nếu một số publish_dates bằng nhau, việc đặt hàng của chúng không cho kết quả xác định, nghĩa là nếu bạn sử dụng LIMITđể phân trang, cuối cùng bạn có thể nhận được cùng một mục trên các trang khác nhau!
Konrad Morawski

Câu trả lời:


244

Nó sẽ đặt hàng trước, sau đó lấy 20. đầu tiên Một cơ sở dữ liệu cũng sẽ xử lý mọi thứ trong WHEREmệnh đề trước ORDER BY.


1
Vậy thời gian có giống nhau không?
Yasar Arafath

7
Sai lầm! LIMITphá vỡ ORDER BY. Với LIMITmột ORDER BYkết quả lợi nhuận sai. LIMITbằng cách nào đó sắp xếp lại kết quả được trả về bởiORDER BY
Green

6
@Green, bạn nhầm rồi. Đọc phần này để được giải thích: dev.mysql.com/doc/refman/5.7/en/limit-optimization.html Khi cột ORDER BY được lập chỉ mục, nó có thể trả về các bản ghi theo thứ tự khác so với không có GIỚI HẠN, khi có nhiều hơn hơn 1 bản ghi có cùng giá trị trong cột đó.
yitwail

1
Một giải pháp nhanh cho các vấn đề như vậy là thêm một cột nữa để đặt hàng bằng cách tốt nhất là có các giá trị duy nhất để cơ sở dữ liệu có quy tắc nhất quán để sắp xếp các hàng khi giá trị của cột theo thứ tự đầu tiên giống nhau cho nhiều hàng.
rineez

37

Mệnh đề LIMIT có thể được sử dụng để hạn chế số lượng hàng được trả về bởi câu lệnh SELECT. LIMIT lấy một hoặc hai đối số số, cả hai phải là hằng số nguyên không âm (trừ khi sử dụng các câu lệnh đã chuẩn bị).

Với hai đối số, đối số thứ nhất chỉ định phần bù của hàng đầu tiên sẽ trả về và đối số thứ hai chỉ định số lượng hàng tối đa sẽ trả về. Độ lệch của hàng ban đầu là 0 (không phải 1):

SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15

Để truy xuất tất cả các hàng từ một độ 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ượng lớn cho tham số thứ hai. Câu lệnh này lấy 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;

Với một đối số, giá trị chỉ định số lượng hàng sẽ trả về từ đầu tập kết quả:

SELECT * FROM tbl LIMIT 5; # Retrieve first 5 rows

Nói cách khác, LIMIT row_count tương đương với LIMIT 0, row_count.

Tất cả chi tiết về: http://dev.mysql.com/doc/refman/5.0/en/select.html


Không phải nó lấy hàng 5-14 sao?
Adonis K. Kakoulidis

@adonis Không, không phải vậy. Ví dụ này đúng từ Tài liệu MySQL
dcaswell

Số 5 là hàng thứ 6. 5 hàng (0 đến 4) được bỏ qua.
Phil Perry

1
Nhưng sử dụng GIỚI HẠN mà không cần ĐẶT HÀNG theo có thể cho kết quả không nhất quán! Thật không may, toàn bộ tập kết quả phải được đặt hàng trước khi LIMIT được áp dụng hoặc DBMS được tự do đặt hàng kết quả và sau đó OFFSET và LIMIT trên tập đó. Tôi đã đọc rằng điều này có thể là do DBMS chọn Kế hoạch truy vấn thay thế dựa trên OFFSET và LIMIT do đó là thứ tự tùy ý.
Barton

4
câu hỏi là yêu cầu giới hạn và đặt hàng bởi. Nhưng câu trả lời hoàn toàn không liên quan đến câu hỏi này
Shen liang

9

Như @James nói, nó sẽ đặt hàng tất cả các bản ghi, sau đó nhận 20 hàng đầu tiên.

Vì nó là như vậy, bạn được đảm bảo để có được 20 bài báo được xuất bản đầu tiên, những bài mới hơn sẽ không được hiển thị.

Trong tình huống của bạn, tôi khuyên bạn nên thêm descvào order by publish_date, nếu bạn muốn các bài viết mới nhất, thì bài viết mới nhất sẽ là đầu tiên.

Nếu bạn cần giữ kết quả theo thứ tự tăng dần, và vẫn chỉ muốn 10 bài viết mới nhất, bạn có thể yêu cầu mysql sắp xếp kết quả của bạn hai lần.

Truy vấn dưới đây sẽ sắp xếp kết quả giảm dần và giới hạn kết quả là 10 (đó là truy vấn bên trong dấu ngoặc đơn). Nó vẫn sẽ được sắp xếp theo thứ tự giảm dần và chúng tôi không hài lòng với điều đó, vì vậy chúng tôi yêu cầu mysql sắp xếp lại một lần nữa. Bây giờ chúng tôi có kết quả mới nhất trên hàng cuối cùng.

select t.article 
from 
    (select article, publish_date 
     from table1
     order by publish_date desc limit 10) t 

order by t.publish_date asc;

Nếu bạn cần tất cả các cột, nó được thực hiện theo cách này:

select t.* 
from 
    (select * 
     from table1  
     order by publish_date desc limit 10) t 

order by t.publish_date asc;

Tôi sử dụng kỹ thuật này khi tôi tự viết các truy vấn để kiểm tra cơ sở dữ liệu cho nhiều thứ khác nhau. Tôi đã không sử dụng nó trong môi trường sản xuất, nhưng bây giờ khi tôi đánh dấu nó, việc sắp xếp thêm không ảnh hưởng đến hiệu suất.


2
Sắp xếp thêm của bạn hầu như không thể có bất kỳ tác động có thể đo lường nào đối với hiệu suất vì nó chỉ giới hạn ở 10 hàng / mục :-). Nói chung, việc sắp xếp một bảng trong bộ nhớ (mà một lựa chọn phụ đang tạo ra) rất nhanh và hầu như không thể đo được trừ khi bạn có hàng triệu hàng hoặc DBMS đang phân trang kết quả được đặt thành đĩa vì nó không phù hợp với bộ nhớ (trong trường hợp đó tùy thuộc vào DBMS, nó cũng có thể hủy bỏ truy vấn).
Martin Kersten

7

Nếu có một chỉ mục phù hợp, trong trường hợp này trên publish_datetrường, thì MySQL không cần quét toàn bộ chỉ mục để lấy 20 bản ghi được yêu cầu - 20 bản ghi sẽ được tìm thấy khi bắt đầu chỉ mục. Nhưng nếu không có chỉ số phù hợp, thì sẽ cần quét toàn bộ bảng.

Có một bài viết Blog hiệu suất MySQL từ năm 2009 về điều này.


7

Bạn có thể thêm [asc] hoặc [desc] vào cuối đơn hàng để có được hồ sơ sớm nhất hoặc mới nhất

Ví dụ, điều này sẽ cung cấp cho bạn các hồ sơ mới nhất đầu tiên

ORDER BY stamp DESC

Nối LIMITmệnh đề sauORDER BY


3
Chào mừng đến với stackoverflow. Tôi nghĩ rằng bạn có thể đã hiểu sai câu hỏi. Tôi tin rằng họ đã hỏi về thứ tự hoạt động hơn là "cách sắp xếp". (Nhưng đó là tranh luận vì câu hỏi đã được trả lời cách đây một thời gian rồi;)
Leigh

5

Bạn có thể sử dụng mã này trong SELECT article FROM table1 ORDER BY publish_date LIMIT 0,10 đó 0 là giới hạn bắt đầu của bản ghi & 10 số bản ghi


8
Không có điều đó là không bắt buộc . LIMIT 10là tốc ký cho LIMIT 0,10.
Lawrence Dol

2
có, không bắt buộc với GIỚI HẠN 0,10 Nhưng bạn có thể yêu cầu như giới hạn này 10,20
gaurangkathiriya

3

GIỚI HẠN thường được áp dụng như thao tác cuối cùng, do đó, kết quả đầu tiên sẽ được sắp xếp và sau đó giới hạn ở 20. Trên thực tế, việc sắp xếp sẽ dừng lại ngay khi tìm thấy 20 kết quả được sắp xếp đầu tiên.


11
Câu thứ hai của bạn đi ngược lại câu đầu tiên của bạn. Sắp xếp không thể dừng khi tìm thấy 20 kết quả đầu tiên vì như bạn đã nói, việc sắp xếp sẽ được thực hiện trước khi kết quả được trả về. MySQL chỉ có thể biết 20 kết quả đầu tiên là gì sau khi sắp xếp xong.
Tom

@Tom, thực tế nó có thể, nếu đặt hàng theo một cột được lập chỉ mục. Nó được giải thích ở đây: dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
yitwail

-3

Ngoài ra cú pháp của LIMIT là khác nhau theo cơ sở dữ liệu, ví dụ:

mysql - GIỚI HẠN 1, 2

postgres - GIỚI HẠN 2 GIỚI THIỆU 1

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.