Tôi đã nghĩ về điều này vài ngày trước sau khi tối ưu hóa SQL. Tôi nghĩ rằng chúng ta có thể đồng ý rằng SQL là một "ngôn ngữ khai báo" theo định nghĩa của Wikipedia:
Mô hình lập trình thể hiện logic tính toán mà không mô tả luồng điều khiển của nó
Nếu bạn nghĩ có bao nhiêu điều được thực hiện sau màn cửa (nhìn vào số liệu thống kê, quyết định xem một chỉ mục có hữu ích không, sẽ tham gia lồng ghép, sáp nhập hoặc băm, v.v.vv ..) logic và cơ sở dữ liệu đã xử lý tất cả logic luồng điều khiển mức thấp.
Cũng trong kịch bản này, đôi khi trình tối ưu hóa cơ sở dữ liệu cần một số "gợi ý" từ người dùng để đưa ra kết quả tốt nhất.
Một định nghĩa phổ biến khác của ngôn ngữ "khai báo" là (Tôi không thể tìm thấy một nguồn có thẩm quyền):
Mô hình lập trình biểu thị kết quả tính toán mong muốn mà không mô tả các bước để đạt được nó (cũng được viết tắt bằng "mô tả cái gì, không phải như thế nào")
Nếu chúng tôi chấp nhận định nghĩa này, chúng tôi gặp phải các vấn đề được mô tả bởi OP.
Vấn đề đầu tiên là SQL cung cấp cho chúng ta nhiều cách tương đương để định nghĩa "cùng một kết quả". Có lẽ đó là một điều ác cần thiết: chúng ta càng trao nhiều sức mạnh cho một ngôn ngữ, thì càng có nhiều cách để thể hiện cùng một điều.
Ví dụ, tôi đã được yêu cầu một lần để tối ưu hóa truy vấn này:
SELECT Distinct CT.cust_type, ct.cust_type_description
from customer c
INNER JOIN
Customer_type CT on c.cust_type=ct.cust_type;
Vì các loại ít hơn nhiều so với khách hàng và có một chỉ số trên cust_type
bảng khách hàng, tôi đã đạt được một sự cải thiện lớn bằng cách viết lại thành:
SELECT CT.cust_type, ct.cust_type_description
from Customer_type CT
Where exists ( select 1 from customer c
Where c.cust_type=ct.cust_type);
Trong trường hợp cụ thể này, khi tôi hỏi nhà phát triển những gì anh ta muốn đạt được, anh ta nói với tôi "Tôi muốn tất cả các loại khách hàng mà tôi có ít nhất một khách hàng", đó chính xác là cách mà truy vấn tối ưu hóa có thể được mô tả.
Vì vậy, nếu tôi có thể tìm thấy một truy vấn tương đương và hiệu quả hơn, tại sao trình tối ưu hóa không thể làm như vậy?
Dự đoán tốt nhất của tôi là vì hai lý do chính:
SQL diễn đạt logic:
vì SQL thể hiện logic mức cao, chúng ta có thực sự muốn trình tối ưu hóa "vượt qua" chúng ta và logic của chúng ta không? Tôi sẽ nhiệt tình hét lên "có" nếu không phải tất cả các lần tôi phải buộc trình tối ưu hóa chọn con đường thực thi hiệu quả nhất. Tôi nghĩ rằng ý tưởng có thể là cho phép trình tối ưu hóa hoạt động tốt nhất (cũng sửa đổi logic của chúng tôi) nhưng cung cấp cho chúng tôi "cơ chế gợi ý" để giải cứu khi có gì đó điên rồ (nó sẽ giống như có bánh xe + phanh một chiếc xe tự trị).
Nhiều lựa chọn hơn = nhiều thời gian hơn
Ngay cả trình tối ưu hóa RDBMS tốt nhất cũng không kiểm tra TẤT CẢ các đường dẫn thực thi có thể, vì chúng phải thực sự nhanh: tối ưu hóa một truy vấn từ 100ms đến 10ms như thế nào nếu tôi cần dành mỗi lần 100ms chọn đường dẫn tốt nhất? Và đó là với trình tối ưu hóa tôn trọng "logic cấp cao" của chúng tôi. Nếu cần kiểm tra tất cả các truy vấn SQL tương đương, thời gian tối ưu hóa có thể tăng lên nhiều lần.
Một ví dụ điển hình khác về truy vấn viết lại không có RDBMS thực sự có khả năng thực hiện là (từ bài đăng blog thú vị này )
SELECT t1.id, t1.value, SUM(t2.value)
FROM mytable t1
JOIN mytable t2
ON t2.id <= t1.id
GROUP BY t1.id, t1.value;
hơn có thể được viết như thế này (Yêu cầu chức năng phân tích)
SELECT id, value, SUM(t1.value) OVER (ORDER BY id)
FROM mytable
select whatever from sometable where FKValue in (select FKValue from sometable_2 where other_value = :param)
. Nó là tầm thường để xem làm thế nào để phục hồi điều đó với mộtexists
hoặc ajoin
.