Có thực sự là thứ tự sẽ không được đảm bảo cho bảng dẫn xuất dự phòng cụ thể này?


11

Tôi tình cờ gặp câu hỏi này trong cuộc trò chuyện trên Twitter với Lukas Eder .

Mặc dù hành vi đúng sẽ là áp dụng mệnh đề ORDER BY cho truy vấn ngoài cùng, bởi vì, ở đây, chúng tôi không sử dụng DISTINCT, GROUP BY, THAM GIA hoặc bất kỳ mệnh đề WHERE nào trong truy vấn ngoài cùng, tại sao RDBMS không vượt qua dữ liệu đến như được sắp xếp bởi các truy vấn bên trong?

SELECT * 
FROM (
    SELECT * FROM table ORDER BY time DESC
) AS t

Khi chạy ví dụ này trên PostgreSQL, ít nhất, bạn sẽ nhận được cùng một Kế hoạch thực thi cho cả truy vấn bên trong và ví dụ bảng dẫn xuất này, cũng như cùng một tập kết quả.

Vì vậy, tôi cho rằng Planner sẽ đơn giản loại bỏ truy vấn ngoài cùng vì nó dư thừa hoặc đơn giản là chuyển qua các kết quả từ bảng bên trong.

Có ai nghĩ rằng điều này có thể không phải là trường hợp?


4
Lưu ý rằng truy vấn của bạn sẽ thất bại trong SQL Server vì một đơn đặt hàng không được phép trong bảng dẫn xuất.
a_horse_with_no_name

Tại sao bạn lại hoài nghi như vậy? Tại sao bạn sẽ giả định bất cứ điều gì? Khi bạn viết một chương trình để lại cho bạn một sự lựa chọn, bạn có mong đợi người dùng mong đợi những điều về lựa chọn của bạn không? Đọc về tối ưu hóa / thực hiện truy vấn logic & vật lý.
philipxy

2
"Tôi cho rằng Planner sẽ đơn giản loại bỏ truy vấn ngoài cùng vì nó dư thừa hoặc đơn giản là chuyển qua các kết quả từ bảng bên trong." Bạn có thể dễ dàng cho rằng Planner sẽ loại bỏ mệnh đề đặt hàng trên truy vấn bên trong vì nó vô nghĩa trong ngữ cảnh.
tự đại diện

MariaDB, khoảng năm 2012, thảo luận về vấn đề này. ThiếuORDER BYdẫnbên trongđể tối ưu hóa khác nhau cho tối đa theo nhóm .
Rick James

1
Trên thực tế, bạn đúng cho Postgres.
Erwin Brandstetter

Câu trả lời:


19

Hầu hết các cơ sở dữ liệu khá rõ ràng về thực tế rằng ORDER BYmột truy vấn con là:

  • Không được phép: Ví dụ: SQL Server, Sybase SQL ở mọi nơi (trừ khi được bổ sung TOPhoặc OFFSET .. FETCH)
  • Vô nghĩa: Ví dụ PostgreSQL, DB2 (một lần nữa, trừ khi được bổ sung OFFSET .. FETCHhoặc LIMIT)

Đây là một ví dụ từ hướng dẫn LUW của DB2 (nhấn mạnh của tôi)

Mệnh đề ORDER BY trong phần phụ không ảnh hưởng đến thứ tự của các hàng được trả về bởi một truy vấn. Mệnh đề ORDER BY chỉ ảnh hưởng đến thứ tự của các hàng được trả về nếu nó được chỉ định trong fullselect ngoài cùng.

Từ ngữ khá rõ ràng, giống như của PostgreSQL :

Nếu sắp xếp không được chọn, các hàng sẽ được trả về theo thứ tự không xác định. Thứ tự thực tế trong trường hợp đó sẽ phụ thuộc vào các loại kế hoạch quét và tham gia và thứ tự trên đĩa, nhưng không được dựa vào . Một thứ tự đầu ra cụ thể chỉ có thể được đảm bảo nếu bước sắp xếp được chọn rõ ràng.

Từ đặc điểm kỹ thuật này, có thể theo dõi rằng bất kỳ thứ tự nào phát sinh từ ORDER BYmệnh đề trong bảng dẫn xuất chỉ là ngẫu nhiên và có thể trùng khớp với thứ tự dự kiến ​​của bạn (điều này có trong hầu hết các cơ sở dữ liệu trong ví dụ tầm thường của bạn), nhưng sẽ không khôn ngoan khi dựa vào điều này.

Lưu ý bên lề về DB2:

Cụ thể, DB2 có một tính năng ít được biết đến hơnORDER BY ORDER OF <table-designator> , có thể được sử dụng như sau:

SELECT C1 FROM
   (SELECT C1 FROM T1
      UNION
    SELECT C1 FROM T2
    ORDER BY C1 ) AS UTABLE
ORDER BY ORDER OF UTABLE

Trong trường hợp cụ thể này, thứ tự của bảng dẫn xuất có thể được sử dụng lại một cách rõ ràng trong hầu hết CHỌN bên ngoài

Lưu ý bên lề về Oracle:

Trong nhiều năm, Oracle đã thực hiện OFFSETphân trang bằng cách sử dụng phân trang ROWNUM, có thể được tính toán hợp lý chỉ sau khi đặt một bảng dẫn xuất:

SELECT *
FROM (
  SELECT rownum AS rn, t.* -- ROWNUM here depends on the derived table's ordering
  FROM (
    SELECT * FROM table ORDER BY time DESC
  ) t
) t
WHERE rn BETWEEN 10 AND 20

Có thể dự đoán một cách hợp lý rằng ít nhất là trong sự hiện diện của ROWNUMmột truy vấn, các phiên bản Oracle trong tương lai sẽ không phá vỡ hành vi này để không phá vỡ tất cả các di sản Oracle SQL ngoài kia, vốn chưa được chuyển sang mong muốn hơn nhiều và OFFSET .. FETCHCú pháp chuẩn SQL có thể đọc được :

SELECT * FROM table ORDER BY time DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY

Meaningless: E.g. PostgreSQLnên thực sự là: "không đáng tin cậy", bởi vì nó nghĩa gì đó. Các hàng được sắp xếp trong truy vấn bên trong và thứ tự đó được giữ ở các mức truy vấn bên ngoài trừ khi được hướng dẫn khác hoặc sắp xếp lại là cơ hội cho các hoạt động bổ sung. Ngay cả khi đó chỉ là một chi tiết thực hiện, nó cũng không vô nghĩa. Điều này có thể được sử dụng cho đầu vào được sắp xếp để tổng hợp các chức năng. Hướng dẫn thậm chí gợi ý càng nhiều: Alternatively, supplying the input values from a sorted subquery will usually work.
Erwin Brandstetter

Câu trích dẫn bạn đã thêm cho Postgres thực sự áp dụng cho một trường hợp khác: các truy vấn hoàn toàn không có ORDER BY.
Erwin Brandstetter

@ErwinBrandstetter: Vui lòng thêm câu trả lời với những chi tiết đó. Cá nhân tôi không đồng ý rằng các chi tiết thực hiện là có ý nghĩa. Mới hôm nay, tôi đã biết rằng ngày xưa, mọi người dựa vào Oracle luôn thực hiện một nhóm được sắp xếp theo hoạt động trong Oracle 8i (tôi tin), đột nhiên, một phiên bản mới hơn đã giới thiệu nhóm băm bởi, điều này đã phá vỡ giả định rằng một số ẩn ý đặt hàng có thể được dựa vào. Nói cách khác: tôi thích đặt nó bằng những từ in đậm. Vô nghĩa , thay vì oh nếu bạn biết các chi tiết phức tạp của phiên bản xyz, bạn thực sự có thể ...
Lukas Eder

Tôi đã thêm một câu trả lời. Cho dù chúng tôi chọn bỏ qua hành vi không chuẩn hoặc chúng tôi có lời khuyên tốt nào khác bên cạnh câu hỏi: Đơn hàng có được đảm bảo cho truy vấn đã cho không? Nó là dành cho Postgres. Nó không (hoặc thậm chí không áp dụng) cho các RDBMS khác. Và điều đó áp dụng cho tất cả các phiên bản hiện tại của Postgres, không chỉ cho phiên bản xyz Nó thậm chí còn được ghi lại (có đặt chỗ). Trích dẫn của bạn là sai lệch. Nếu chúng ta muốn bỏ qua hành vi không chuẩn, chúng ta có thể bắt đầu với Oracle khiến chúng ta tin rằng NULL và chuỗi rỗng giống nhau. Cũng trực giao cho câu hỏi.
Erwin Brandstetter

@ErwinBrandstetter: Thú vị, cảm ơn vì đã cập nhật. Đây có phải là đảm bảo rằng bạn đang đề cập đến tài liệu?
Lukas Eder

12

Đúng. Không có một ORDER BYmệnh đề, thứ tự đầu ra không được xác định và trình hoạch định truy vấn cũng nằm trong phạm vi của nó để cho rằng bạn biết và hiểu điều này.

Nó có thể quyết định rằng vì truy vấn bên ngoài không chỉ định một đơn đặt hàng nên nó có thể bỏ thứ tự trong truy vấn bên trong để tránh thao tác sắp xếp, đặc biệt là nếu không có chỉ mục được nhóm hoặc hoàn toàn không có chỉ mục để hỗ trợ đơn hàng. Nếu không, bây giờ nó có thể làm trong các phiên bản trong tương lai.

Không bao giờ dựa vào hành vi không xác định. Nếu bạn cần một thứ tự cụ thể, đưa ra một ORDER BYđiều khoản ở nơi thích hợp.


Khi kiểm tra nó trên PostgreSQL, việc sắp xếp được thực hiện sau khi quét tuần tự vì tôi không có bất kỳ chỉ mục nào trên cột được sử dụng bởi ORDER BY. RDBMS nào bạn nghĩ sẽ bỏ qua truy vấn bên trong ĐẶT HÀNG?
Vlad Mihalcea

5
Tôi không thể nói tôi biết bất kỳ điều gì sẽ xảy ra , chỉ là họ có thể hoàn toàn tự do làm điều đó nếu họ muốn - đó sẽ là một sự tối ưu hóa hoàn toàn chấp nhận được theo cả tiêu chuẩn chung và thông số kỹ thuật của sản phẩm. SQL Server sẽ từ chối hoàn toàn truy vấn (trừ khi bạn bao gồm TOP 100%để truy vấn hiện tại không khả chuyển, nên đó là ưu tiên cho dự án của bạn. Bởi vì Postgres tuân theo thứ tự trong truy vấn bên trong bây giờ không có nghĩa là nó sẽ luôn luôn làm trong tương lai (hoặc thực tế là các phiên bản cũ hơn, vì vậy bạn nên tránh dựa vào hành vi chỉ trong trường hợp.
David Spillett

1
@VladMihalcea một DBMS "tối ưu hóa" dự phòng ORDER BYMariaDB: Tại sao ĐẶT HÀNG
ypercubeᵀᴹ

6

Đó là vấn đề rất lớn với hành vi không xác định - hoạt động cho bạn, hoạt động với tôi, định dạng lại ổ cứng trong prod;)

Chúng ta có thể lùi lại một bước và nói rằng theo một nghĩa nào đó, bạn đúng - không có lý do trần tục tại sao bất kỳ RDBMS lành mạnh nào sẽ sắp xếp lại các hàng trong lựa chọn bên trong. Nhưng nó không được bảo đảm - có nghĩa là trong tương lai có thể có một lý do và các nhà cung cấp có thể tự do làm điều đó. Có nghĩa là bất kỳ mã nào dựa trên hành vi này đều là sự thay đổi mà nhà cung cấp có thể thực hiện mà họ không có nghĩa vụ phải công khai, vì đó không phải là một thay đổi vi phạm từ API POV.


2
Một lý do nó có thể tối ưu hóa thứ tự bằng cách là tốc độ. Trả lại các hàng theo thứ tự khác nhau có thể hiệu quả hơn.
TomTom

2
Cụ thể, máy chủ có thể khai thác song song để đọc bảng. Nếu đúng như vậy và không cần thực thi một đơn đặt hàng, bạn sẽ lấy lại các hàng theo các chủ đề đọc chúng. (Máy chủ SQL thực sự làm điều này, do đó, SELECTviệc không ORDER BYthực sự là không xác định và không chỉ trên lý thuyết hoặc vì dữ liệu đã thay đổi.)
Jeroen Mostert

@JeroenMostert: Hành vi không xác định chỉ trở nên tồi tệ hơn. Điều gì xảy ra nếu nó không theo thứ tự và delta được sử dụng để lập chỉ mục thành một mảng?
Joshua

2

Có thực sự là thứ tự sẽ không được đảm bảo cho bảng dẫn xuất dự phòng cụ thể này?

Câu trả lời cho tất cả các phiên bản Postgres hiện tại (mà bạn đang thử nghiệm) là: Không - cho truy vấn cụ thể này. Sắp xếp thứ tự được đảm bảo.

Người dùng máy chủ SQL sẽ không thoải mái với điều này vì Microsoft thậm chí không cho phép ORDER BYtrong các truy vấn con. Thứ tự sắp xếp được đảm bảo cho truy vấn đơn giản này trong Postgres. ORDER BYđược áp dụng trong truy vấn con và truy vấn bên ngoài không làm bất cứ điều gì có thể thay đổi thứ tự.

Hướng dẫn thậm chí còn gợi ý nhiều như trong chương Hàm tổng hợp :

Ngoài ra, việc cung cấp các giá trị đầu vào từ một truy vấn con được sắp xếp thường sẽ hoạt động.

Lưu ý điều này chỉ đúng trong khi các mức truy vấn bên ngoài không thêm các thao tác có thể thay đổi thứ tự. Vì vậy, nó chỉ "được bảo đảm" cho trường hợp đơn giản và không được hỗ trợ bởi tiêu chuẩn SQL. Postgres được tự do sắp xếp lại nếu đó là cơ hội cho các hoạt động bổ sung. Trong trường hợp nghi ngờ thêm mộtORDER BY cho bên ngoài SELECT. (Trong trường hợp đó, bên trong ORDER BYsẽ là tiếng ồn dư thừa cho truy vấn đơn giản này.)


Có đúng không khi "table"một bảng cơ sở đơn giản mà là một khung nhìn phức tạp hoặc một bảng được phân vùng? Có đúng không khi kế hoạch cũng thực hiện song song? Điều đó có đúng trong Postgres 10 không? (Tôi chỉ hỏi, tôi không chắc câu trả lời của bất kỳ câu hỏi nào trong số này.)
ypercubeᵀᴹ

@ ypercubeᵀᴹ: Tôi chưa thử nghiệm Postgres 10 cho tất cả những thứ này, nhưng tôi khá chắc chắn rằng nó đúng trong mọi trường hợp. Thứ tự được áp dụng và không thay đổi trong truy vấn bên ngoài cho trường hợp đơn giản.
Erwin Brandstetter
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.