2008-12-19 43 views
13

Tôi vừa mới phát hiện ra rằng việc thực hiện kế hoạch thực hiện giữa hai câu lệnh select Sau đây là ồ ạt khác nhau:ngạc nhiên tốc độ tăng SQL

select * from your_large_table 
where LEFT(some_string_field, 4) = '2505' 

select * from your_large_table 
where some_string_field like '2505%' 

Các kế hoạch thực hiện lần lượt là 98% và 2%. Bit của một sự khác biệt về tốc độ sau đó. Tôi đã thực sự bị sốc khi tôi nhìn thấy nó.

Tôi luôn luôn thực hiện LEFT (xxx) = 'yyy' khi nó đọc tốt. Tôi thực sự tìm thấy điều này bằng cách kiểm tra LINQ được tạo ra với SQL được tạo bằng tay. Tôi cho rằng lệnh LIKE sẽ chậm hơn, nhưng thực tế lại nhanh hơn rất nhiều.

Câu hỏi của tôi là tại sao LEFT() chậm hơn so với LIKE '% ..'. Họ là afterall giống hệt nhau?

Ngoài ra, có một lần truy cập CPU bằng cách sử dụng LEFT() không?

Trả lời

23

Nói chung, bạn không bao giờ nên sử dụng hàm ở bên trái của mệnh đề WHERE trong truy vấn. Nếu bạn làm như vậy, SQL sẽ không sử dụng một chỉ mục - nó phải đánh giá hàm cho mỗi hàng của bảng.Mục đích là để đảm bảo rằng mệnh đề where của bạn là "Sargable"

Một số ví dụ khác:

Bad: Select ... WHERE isNull(FullName,'') = 'Ed Jones' 
Fixed: Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL)) 

Bad: Select ... WHERE SUBSTRING(DealerName,4) = 'Ford' 
Fixed: Select ... WHERE DealerName Like 'Ford%' 

Bad: Select ... WHERE DateDiff(mm,OrderDate,GetDate()) >= 30 
Fixed: Select ... WHERE OrderDate < DateAdd(mm,-30,GetDate()) 

Bad: Select ... WHERE Year(OrderDate) = 2003 
Fixed: Select ... WHERE OrderDate >= '2003-1-1' AND OrderDate < '2004-1-1' 
+1

Typeof trong dòng thứ 2, nó không hoàn toàn giống nhau. –

+0

Ví dụ tuyệt vời! Nhờ bạn, tôi không phải tự hỏi câu hỏi của mình. :) – Ecyrb

+0

Ai đó có vẻ đã sao chép các ví dụ của bạn, với các thay thế nhỏ, vào bài viết wikipedia. Sự thay thế của '' Ford'' với '' Toyota'' đặc biệt là nói. –

7

Có tác động lớn đến việc sử dụng các cuộc gọi hàm trong các mệnh đề ở đâu khi SQL Server phải tính kết quả cho mỗi hàng. Mặt khác, like là tính năng ngôn ngữ được tích hợp được tối ưu hóa cao.

3

Nếu bạn sử dụng một chức năng trên một cột với một chỉ số thì db không còn sử dụng chỉ số (ít nhất là với Oracle anyway)
Vì vậy, tôi đoán rằng ví dụ lĩnh vực của bạn 'some_string_field' có một chỉ mục trên nó mà doesn Không được sử dụng cho truy vấn với 'LEFT'

+0

Điều này không hoàn toàn đúng. Chỉ số vẫn có thể được sử dụng nhưng có thể theo một cách khác. Nếu số lượng phù hợp dự kiến ​​trên vị từ nhỏ và chỉ mục nhỏ hơn nhiều so với tabe thì chỉ số quét toàn bộ hoặc nhanh có thể được tận dụng. –

+0

Thú vị, cảm ơn thông tin – hamishmcn

17

Có vẻ như biểu thức LEFT (some_string_field, 4) được đánh giá cho mỗi hàng quét toàn bộ bảng, trong khi biểu thức "thích" sẽ sử dụng chỉ mục.

Tối ưu hóa "thích" để sử dụng chỉ mục nếu đó là mẫu được neo trước là một tối ưu hóa dễ dàng hơn nhiều so với việc phân tích các biểu thức tùy ý liên quan đến các hàm chuỗi.

1

Tại sao bạn nói chúng giống hệt nhau? Họ có thể giải quyết cùng một vấn đề, nhưng cách tiếp cận của họ là khác nhau. Ít nhất có vẻ như ...

Truy vấn bằng cách sử dụng LEFT tối ưu hóa thử nghiệm vì nó đã biết về độ dài của tiền tố và v.v., vì vậy trong chương trình C/C++/... hoặc không có chỉ mục , một thuật toán sử dụng LEFT để thực hiện một hành vi LIKE nhất định sẽ là nhanh nhất. Nhưng ngược lại với hầu hết các ngôn ngữ không khai báo, trên một cơ sở dữ liệu SQL, rất nhiều tối ưu hóa op được thực hiện cho bạn. Ví dụ LIKE có thể được thực hiện bằng cách đầu tiên tìm kiếm dấu% và nếu nó được nhận thấy rằng% là char cuối cùng trong chuỗi, truy vấn có thể được tối ưu hóa nhiều theo cách tương tự như bạn đã sử dụng LEFT, nhưng trực tiếp sử dụng một chỉ mục .

Vì vậy, thực sự tôi nghĩ rằng bạn ngay sau khi tất cả, họ có thể là giống hệt nhau trong cách tiếp cận của họ. Sự khác biệt duy nhất là máy chủ db có thể sử dụng một chỉ mục trong truy vấn bằng cách sử dụng LIKE vì không có một hàm nào chuyển đổi giá trị cột thành một cái gì đó không rõ trong mệnh đề WHERE.

+0

Dấu '%' là ký tự đại diện cho LIKE, Fred. –

+0

Umm Tôi không thể không đồng ý, quan điểm của tôi là db có thể đã tối ưu hóa "giống như 'xxx%'" thành "trái" (a, 3) = 'xxx' "nhưng điều đó không quan trọng vì cơ sở dữ liệu có thể sử dụng chỉ mục, vì vậy nó sẽ luôn luôn được nhanh hơn anyway. – FredV

1

gì xảy ra ở đây là một trong hai rằng RDBMS là không có khả năng sử dụng một chỉ mục trên LEFT() vị ngữ và có khả năng sử dụng nó trên LIKE, hoặc nó chỉ đơn giản là thực hiện các cuộc gọi sai trong đó sẽ là phương pháp truy cập thích hợp hơn. Thứ nhất, nó có thể đúng đối với một số RDBMS áp dụng một chức năng cho một cột ngăn chặn một phương pháp truy cập dựa trên chỉ mục không được sử dụng, nhưng đó không phải là một sự thật phổ quát, cũng không có lý do hợp lý nào tại sao nó cần phải . Một phương pháp truy cập dựa trên chỉ mục (như quét chỉ mục đầy đủ của Oracle hoặc quét chỉ mục đầy đủ của Oracle) có thể có ích nhưng trong một số trường hợp RDBMS không có khả năng hoạt động trong ngữ cảnh của một vị từ dựa trên hàm.

Thứ hai, trình tối ưu hóa có thể đơn giản nhận sai số học trong việc ước tính lợi ích của các phương thức truy cập khả dụng khác nhau. Giả sử rằng hệ thống có thể thực hiện một phương pháp truy cập dựa trên chỉ mục, trước tiên nó ước tính số hàng phù hợp với vị từ, từ thống kê trên bảng, thống kê trên cột, bằng cách lấy mẫu dữ liệu tại thời gian phân tích cú pháp, hoặc đang sử dụng quy tắc heuristic (ví dụ: "giả sử 5% hàng sẽ khớp"). Sau đó, nó phải đánh giá các chi phí tương đối của việc quét toàn bộ bảng hoặc các phương pháp dựa trên chỉ mục có sẵn. Đôi khi nó sẽ nhận được số học sai, đôi khi các số liệu thống kê sẽ được gây hiểu lầm hoặc không chính xác, và đôi khi các quy tắc heuristic sẽ không thích hợp cho các tập dữ liệu.

Điểm mấu chốt là phải nhận thức được một số vấn đề:

  1. gì hoạt động có thể hỗ trợ RDBMS của bạn?
  2. Hoạt động nào thích hợp nhất trong trường hợp bạn đang làm việc cùng?
  3. Lựa chọn của hệ thống có đúng không?
  4. Điều gì có thể được thực hiện để cho phép hệ thống thực hiện thao tác hiệu quả hơn (ví dụ: thêm một hạn chế không bị thiếu, cập nhật số liệu thống kê v.v.)?

Theo kinh nghiệm của tôi, đây không phải là một nhiệm vụ tầm thường và thường là tốt nhất cho các chuyên gia. Hoặc mặt khác, chỉ cần đăng vấn đề lên Stackoverflow - một số người trong chúng ta thấy công cụ này hấp dẫn, con chó giúp chúng ta.

1

Như @BradC đã đề cập, bạn không nên sử dụng các hàm trong mệnh đề WHERE nếu bạn có chỉ mục và muốn tận dụng chúng.

Nếu bạn đọc phần có tiêu đề "Sử dụng LIKE thay vì LEFT() hoặc SUBSTRING() trong mệnh đề WHERE khi chỉ mục có" from these SQL Performance Tips, có nhiều ví dụ hơn.

Nó cũng gợi ý các câu hỏi bạn sẽ gặp phải trên số MCSE SQL Server 2012 exams nếu bạn cũng quan tâm đến việc tham gia những câu hỏi đó. :-)

+0

Tôi đã nhấp vào liên kết chỉ để xem các gợi ý câu hỏi đó. Không có nhiều ở đó, nhưng không có gì thú vị khi những câu hỏi đó thậm chí còn bị ám chỉ. –

Các vấn đề liên quan