Là khai báo SQL?


22

Tôi hỏi bởi vì rất nhiều câu hỏi tôi thấy trong SQL có nghĩa là: "Cái này chậm. Làm thế nào để tôi tăng tốc"? Hoặc là các hướng dẫn nêu rõ "Làm theo cách này và không phải theo cách đó vì nó nhanh hơn".

Dường như với tôi, một phần lớn SQL đang biết cách biểu thức sẽ được thực hiện và từ kiến ​​thức đó chọn các kiểu biểu thức hoạt động tốt hơn. Điều này không vuông với một khía cạnh của lập trình khai báo - đó là việc rời khỏi hệ thống để quyết định cách tốt nhất để thực hiện phép tính với bạn chỉ cần xác định những gì phép tính sẽ tạo ra.

Nên không phải là một công cụ SQL không quan tâm đến nếu bạn sử dụng in, existshoặc joinnếu nó thực sự là khai báo không nên nó chỉ cung cấp cho bạn câu trả lời đúng trong thời gian hợp lý nếu có thể bởi bất kỳ trong ba phương pháp? Ví dụ cuối cùng này được nhắc bởi bài đăng gần đây thuộc loại được đề cập trong đoạn mở đầu của tôi.

Chỉ mục

Tôi đoán ví dụ đơn giản nhất tôi có thể đã sử dụng liên quan đến việc tạo chỉ mục cho bảng. Gumph ở đây trên w3schools.com thậm chí còn cố gắng giải thích nó như một thứ mà người dùng không thấy được vì lý do hiệu suất. Mô tả của họ dường như đặt các chỉ số SQL vào trại không khai báo và chúng thường được thêm bằng tay vì lý do hiệu suất hoàn toàn.

Có phải trường hợp của họ ở đâu đó là một DB DB lý tưởng có tính khai báo cao hơn nhiều so với tất cả các phần còn lại nhưng vì đó là điều tốt mà người ta không nghe về nó?


@FrustratedWithFormsDesigner: Tôi biết chính xác điều đó có nghĩa là gì. 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ột existshoặc a join.
Mason Wheeler

Sử dụng lý luận tương tự tôi đoán các biểu thức chính quy là một phương thức biểu đạt khai báo hơn vì tôi hiếm khi thấy các câu hỏi về hiệu suất được trả lời bởi "bạn nên viết nó theo cách này để có hiệu suất tốt hơn". Tôi đang làm mất trí não của mình và có thể nhớ một nửa câu hỏi để làm với những khẳng định tiêu cực về phía trước hoặc phía trước trong một regrec chậm trong đó câu trả lời là viết lại regrec theo cách khác để làm điều tương tự trong thời gian ngắn hơn.
Paddy3118

Hiệu suất là một chi tiết thực hiện. Hiệu năng của gần như bất kỳ triển khai IN nào cũng có thể tương đương hoặc tốt hơn EXISTS và THAM GIA nếu các nhà phát triển bộ xử lý truy vấn cảm thấy đó là ưu tiên.
JustinC

1
@JustinC, nó dường như không chỉ là một chi tiết được ưu tiên cho các câu hỏi và lời khuyên về SQL theo định hướng hiệu năng cho một ngôn ngữ được cho là khai báo?
Paddy3118

Không có định nghĩa rõ ràng về ngôn ngữ lập trình khai báo, và vì vậy thật vô nghĩa khi nói về nó. Một số ngôn ngữ có trình độ cao hơn những ngôn ngữ khác, đó là tất cả.
vườn

Câu trả lời:


21

SQL là lý thuyết khai báo. Nhưng bạn biết họ nói gì về sự khác biệt giữa lý thuyết và thực hành ...

Về cốt lõi, khái niệm "lập trình khai báo" chưa bao giờ thực sự hiệu quả và có khả năng sẽ không bao giờ cho đến khi chúng ta có một trình biên dịch dựa trên AI có khả năng xem mã và trả lời câu hỏi "ý định của mã này là gì?" một cách thông minh, giống như cách người viết nó sẽ làm. Trọng tâm của mọi ngôn ngữ khai báo là cả đống mã mệnh lệnh đang cố gắng điên cuồng để giải quyết vấn đề đó mà không cần sự trợ giúp của AI.

Thông thường nó hoạt động tốt một cách đáng ngạc nhiên, bởi vì những trường hợp phổ biến nhất là những trường hợp phổ biến , mà những người viết ra ngôn ngữ này đã biết và tìm ra những cách tốt để xử lý. Nhưng sau đó, bạn gặp phải một trường hợp khó khăn mà người triển khai không xem xét và bạn thấy hiệu suất giảm xuống nhanh chóng vì trình thông dịch buộc phải lấy mã theo nghĩa đen nhiều hơn và xử lý nó theo cách kém hiệu quả hơn.


3
Không bao giờ thực sự hiệu quả? SQL, LINQ, Knockout.js, Prolog, ngôn ngữ ELM. Bạn có thể muốn kiểm tra lại. Tôi đang sử dụng công nghệ khai báo chủ yếu vào lúc này.
brian

5
@brian: Và tất cả chúng đều thoái hóa khá nhanh khi bạn gặp phải trường hợp cạnh mà không ai nghĩ tới. Tôi cho rằng lẽ ra tôi nên nói "không bao giờ thực sự hiệu quả trong trường hợp chung ".
Mason Wheeler

Khi nào câu trả lời của bạn được đặt xuống cấp khi thấy nó được lưu trữ trong cơ sở dữ liệu SQL Server như thế nào? :) Tôi hiếm khi gặp trường hợp cạnh trong bất kỳ trường hợp nào không thể giải quyết trong khuôn khổ. Tôi thấy bạn đến từ đâu nhưng các trường hợp thực sự không gây cho tôi nhiều đau đớn vì lý do có lợi và dễ dàng để lý giải khoảng 99% mã khai báo. Giống như nói Clojure hoặc F # là xấu vì bạn phải sử dụng một loại có thể thay đổi để giải quyết vấn đề của mình.
brian

11
@brian: I rarely hit an edge case in any of them that couldn't be solved within the framework.Vâng, đó là toàn bộ vấn đề: phải tìm ra cách giải quyết chúng trong khuôn khổ vì khung không đủ thông minh để giải quyết nó cho bạn theo cách bạn tuyên bố ban đầu.
Mason Wheeler

Còn chọn ... để cập nhật thì sao? Có vẻ như một mệnh lệnh bắt buộc.
Jesvin Jose

6

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_typebả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

1
Ví dụ về việc viết lại sự tham gia để tồn tại thật thú vị. Một nguyên tắc nhỏ mà tôi cố gắng gây ấn tượng với các nhà phát triển SQL là việc sử dụng DISTINCT là mùi mã - hoặc truy vấn, hoặc mô hình dữ liệu, rất có thể sai và nên tìm cách tiếp cận khác.
David Aldridge
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.