Hiệu suất SQL 'like' vs '='


82

Câu hỏi này xoay quanh những gì tôi đang thắc mắc, nhưng câu trả lời không giải quyết chính xác nó.

Có vẻ như nói chung '=' nhanh hơn 'like' khi sử dụng các ký tự đại diện. Đây dường như là sự khôn ngoan thông thường. Tuy nhiên, giả sử tôi có một cột chứa một số giới hạn các số nhận dạng varchar cố định, được mã hóa cứng, và tôi muốn chọn tất cả các hàng khớp với một trong số chúng:

select * from table where value like 'abc%'

select * from table where value = 'abcdefghijklmn'

'Like' chỉ cần kiểm tra ba ký tự đầu tiên để tìm kết quả khớp, trong khi '=' phải so sánh toàn bộ chuỗi. Trong trường hợp này, đối với tôi, dường như 'like' sẽ có lợi thế hơn, tất cả những thứ khác đều bình đẳng.

Đây là một câu hỏi tổng quát, mang tính học thuật, và do đó không phải là DB nào, nhưng nó đã nảy sinh khi sử dụng SQL Server 2005.


23
Một điều chính mà bạn bỏ qua là liệu có valueđược lập chỉ mục hay không . Nếu đúng như vậy, thì đó =là một cách tra cứu đơn giản mà không cần quét bảng và sẽ đánh bật mọi LIKEtuyên bố mà bạn ném vào nó.
Daniel DiPaolo

7
@Daniel Tôi nghĩ điều đó không chính xác. A LIKEcó ký tự đại diện ở cuối là SARGable và do đó sẽ thực hiện tìm kiếm phạm vi trên một chỉ mục, không cần quét bảng trong tầm nhìn. Tìm kiếm phạm vi đó có thể cạnh tranh khá dễ dàng với một =tuyên bố và trong nhiều trường hợp (chẳng hạn như nếu tất cả các hàng thỏa mãn nằm trên một trang, một điều kiện không khó xảy ra) có thể có cùng hiệu suất, kéo theo cùng một số lần đọc.
ErikE

"Tất cả những thứ khác đều bình đẳng" của tôi nhằm đề cập đến vấn đề "được lập chỉ mục hay không", nhưng dường như có ít nhất một số tranh cãi về mức độ khác biệt sẽ tạo ra, theo nhận xét của tôi về các câu trả lời khác.
MickeyfAgain_BeforeExitOfSO

Hãy xem câu trả lời của tôi. Ban đầu, tôi đã thử nghiệm unindexed và hiệu suất giống hệt nhau (cả hai lần quét bảng đều giống hệt nhau). Tôi đã giả định đối với kịch bản thử nghiệm của mình rằng nó sẽ được lập chỉ mục, nếu không thì tại sao bạn lại quan tâm đến hiệu suất?
JNK

5
Tất cả những câu nói về 'thích' trong câu hỏi này và câu trả lời khiến chúng ta nghe như một đám nữ sinh trung học. Giống như, hoàn toàn.
JulianR

Câu trả lời:


64

Xem https://web.archive.org/web/20150209022016/http://myitforum.com/cs2/blogs/jnelson/archive/2007/11/16/108354.aspx

Trích dẫn từ đó:

các quy tắc sử dụng chỉ mục với LIKE lỏng lẻo như thế này:

  • Nếu tiêu chí bộ lọc của bạn sử dụng = = và trường được lập chỉ mục, thì rất có thể nó sẽ sử dụng INDEX / CLUSTERED INDEX XEM

  • Nếu tiêu chí bộ lọc của bạn sử dụng LIKE, không có ký tự đại diện (chẳng hạn như nếu bạn có một tham số trong báo cáo web CÓ% nhưng thay vào đó bạn sử dụng chuỗi đầy đủ), thì khả năng là số 1 để sử dụng chỉ mục. Chi phí tăng lên gần như không có gì.

  • Nếu tiêu chí bộ lọc của bạn sử dụng LIKE, nhưng có ký tự đại diện ở đầu (như trong Name0 LIKE '% UTER') thì ít có khả năng sử dụng chỉ mục hơn, nhưng ít nhất nó vẫn có thể thực hiện QUÉT CHỈ SỐ trên phạm vi đầy đủ hoặc một phần của chỉ số.

  • TUY NHIÊN, nếu tiêu chí bộ lọc của bạn sử dụng LIKE, nhưng bắt đầu bằng STRING ĐẦU TIÊN và có các ký tự đại diện ở đâu đó SAU ĐÓ (như trong Name0 LIKE 'COMP% ER'), thì SQL có thể chỉ sử dụng INDEX XEM để nhanh chóng tìm thấy các hàng có cùng một đầu tiên các ký tự bắt đầu, và sau đó xem qua các hàng đó để có kết quả khớp chính xác.

(Cũng nên nhớ rằng, công cụ SQL vẫn có thể không sử dụng chỉ mục theo cách bạn mong đợi, tùy thuộc vào những gì khác đang diễn ra trong truy vấn của bạn và những bảng bạn đang tham gia. Công cụ SQL có quyền viết lại truy vấn một chút để lấy dữ liệu theo cách mà nó cho là hiệu quả nhất và điều đó có thể bao gồm QUÉT CHỈ SỐ thay vì XEM CHỈ SỐ)


1
liên kết là chết
baxx

2
@baxx một bản sao của liên kết có sẵn trong máy quay lui. web.archive.org/web/20150209022016/http://myitforum.com/cs2/…
alphabet5

45

Đó là một sự khác biệt có thể đo lường được.

Chạy như sau:

Create Table #TempTester (id int, col1 varchar(20), value varchar(20))
go

INSERT INTO #TempTester (id, col1, value)
VALUES
(1, 'this is #1', 'abcdefghij')
GO

INSERT INTO #TempTester (id, col1, value)
VALUES
(2, 'this is #2', 'foob'),
(3, 'this is #3', 'abdefghic'),
(4, 'this is #4', 'other'),
(5, 'this is #5', 'zyx'),
(6, 'this is #6', 'zyx'),
(7, 'this is #7', 'zyx'),
(8, 'this is #8', 'klm'),
(9, 'this is #9', 'klm'),
(10, 'this is #10', 'zyx')
GO 10000

CREATE CLUSTERED INDEX ixId ON #TempTester(id)CREATE CLUSTERED INDEX ixId ON #TempTester(id)

CREATE NONCLUSTERED INDEX ixTesting ON #TempTester(value)

Sau đó:

SET SHOWPLAN_XML ON

Sau đó:

SELECT * FROM #TempTester WHERE value LIKE 'abc%'

SELECT * FROM #TempTester WHERE value = 'abcdefghij'

Kết quả thực hiện kế hoạch cho bạn thấy rằng chi phí của hoạt động đầu tiên, LIKEso sánh, đắt hơn khoảng 10 lần so với =so sánh.

Nếu bạn có thể sử dụng một =so sánh, vui lòng làm như vậy.


2
+1 để thực sự thử nghiệm nó. Mặc dù vậy, chỉ nhìn vào kế hoạch có thể không nói được toàn bộ câu chuyện. Tôi sẽ thực hiện một số thử nghiệm của riêng mình và sẽ cho mọi người biết nếu tôi phát hiện ra điều gì bất ngờ.
Tom H

1
Tom - đúng, nhưng nó đã cho tôi đủ dấu hiệu rằng cả hai KHÔNG được xử lý giống nhau ở hậu trường.
JNK

1
Các chi phí hiển thị trong kế hoạch thực hiện là sai. Chúng không phản ánh hiệu suất thực tế. Trong kế hoạch đầu tiên, chúng dựa trên số lượng hàng ước tính của 19.95SQL Server như vậy chi phí trong 19 tra cứu chính bổ sung mà không bao giờ thành hiện thực trong thực tế (Ngay cả trong kế hoạch thực thi thực tế , chi phí được hiển thị dựa trên Chi phí cây con ước tính )
Martin Smith

Tôi vừa thực hiện thử nghiệm của bạn cũng như thử nghiệm có khoảng 1 triệu hàng và trong cả hai trường hợp, hiệu suất và kế hoạch truy vấn đều giống hệt nhau. Đây là trên SQL 2008 vì tôi không có 2005 trên máy này.
Tom H

1
@JNK - chỉ cần thử nó - có một sự khác biệt không đáng kể, tuy nhiên, sự chênh lệch là như nhau. 327ms cho LIKE, 203ms cho =. Tôi hy vọng nếu tôi chạy nhiều thử nghiệm hơn và lấy số trung bình chính xác, sẽ không có sự khác biệt thực sự giữa #temp và bảng thực.
Sẽ A

13

Bạn cũng nên nhớ rằng khi sử dụng like, một số hương vị sql sẽ bỏ qua các chỉ mục và điều đó sẽ giết chết hiệu suất. Điều này đặc biệt đúng nếu bạn không sử dụng mẫu "bắt đầu với" như ví dụ của bạn.

Bạn thực sự nên nhìn vào kế hoạch thực thi cho truy vấn và xem nó đang làm gì, đoán càng ít càng tốt.

Điều này đang được nói, mẫu "bắt đầu với" có thể và được tối ưu hóa trong máy chủ sql. Nó sẽ sử dụng chỉ mục bảng. EF 4.0 được chuyển sang likeStartsWithlý do này.


2
Không có cơ sở dữ liệu quan hệ nào có giá trị là muối của nó sẽ bỏ qua chỉ mục khi mẫu tương tự là một phần của truy vấn và ký tự đại diện đang ở sau. Đó có thể là một câu chuyện khác nếu bạn đang ràng buộc giá trị và cơ sở dữ liệu hỗ trợ ràng buộc tách biệt với chuẩn bị truy vấn.
Dave W. Smith

Đó là những gì ruột của tôi cũng nói với tôi, nhưng tôi chỉ có kinh nghiệm thực tế với máy chủ sql về vấn đề này, vì vậy tôi tập trung vào nó một cách cụ thể.
Blindy

7

Nếu không valueđược lập chỉ mục, cả hai đều dẫn đến việc quét bảng. Sự khác biệt về hiệu suất trong kịch bản này sẽ không đáng kể.

Nếu valueđược lập chỉ mục, như Daniel đã chỉ ra trong bình luận của mình, =kết quả sẽ dẫn đến tra cứu chỉ mục là hiệu suất O (log N). LIKE sẽ (rất có thể - tùy thuộc vào mức độ chọn lọc của nó) dẫn đến việc quét một phần chỉ mục >= 'abc'< 'abd'sẽ đòi hỏi nhiều nỗ lực hơn =.

Lưu ý rằng tôi đang nói về SQL Server ở đây - không phải tất cả các DBMS đều sẽ tốt với LIKE.


Tôi không nghĩ rằng bạn biết cách hoạt động của tìm kiếm nhị phân. Cả =trường hợp và like '...%'trường hợp đều hoạt động giống nhau nếu sql nhận ra mẫu (và nó có), bởi vì trong cả hai trường hợp, cây con được chọn dựa trên quan hệ so sánh.
Blindy

Ồ, tôi làm. LIKE rất có thể sẽ hoạt động tồi tệ hơn mặc dù nó vẫn sẽ là O (log N) nếu độ chọn lọc đủ cao - O (log N) để tìm ra nơi bắt đầu quét một phần từ đó, sau đó một số lần đọc chuyển tiếp qua chỉ mục cho đến khi điểm cuối 'abd'đã đạt được.
Sẽ A

Có nhưng ví dụ của OP giả định chỉ có một giá trị trong phạm vi đó, vì vậy, với suy nghĩ đó, các so sánh sẽ giống hệt nhau.
Blindy

Điểm hợp lệ - không hoàn toàn rõ ràng rằng đây là những gì OP đã nói, nhưng tôi nghĩ có nhiều khả năng là trường hợp này hơn không. Trong trường hợp đó, hiệu suất sẽ giống hệt nhau.
Sẽ A

Phạm vi tìm kiếm của một LIKE có thể sẽ cạnh tranh khá dễ dàng với câu lệnh = và trong nhiều trường hợp (chẳng hạn như nếu tất cả các hàng thỏa mãn nằm trên một trang, một điều kiện không khó xảy ra) có thể có cùng hiệu suất, dẫn đến cùng một số lần đọc . Tôi nghĩ rằng nói "sẽ đòi hỏi nhiều nỗ lực hơn" là một câu nói sai lầm.
ErikE

5

Bạn đang đặt câu hỏi sai. Trong cơ sở dữ liệu, hiệu suất của toán tử không phải là vấn đề quan trọng, mà luôn luôn là Tính khả thi của biểu thức và tính khả thi của truy vấn tổng thể. Bản thân hiệu suất của nhà điều hành phần lớn không liên quan.

Vì vậy, làm thế nào để làm LIKE=so sánh về SARGability? LIKE, khi được sử dụng với một biểu thức không bắt đầu bằng một hằng số (ví dụ: khi được sử dụng LIKE '%something') theo định nghĩa không phải là SARGabale. Nhưng điều đó có làm cho =hay LIKE 'something%'SARGable không? Không. Như với bất kỳ câu hỏi nào về hiệu suất SQL, câu trả lời không nằm ở truy vấn của văn bản mà nằm ở lược đồ được triển khai. Các biểu thức này có thể là SARGable nếu tồn tại một chỉ mục để đáp ứng chúng.

Vì vậy, sự thật mà nói, có sự khác biệt nhỏ giữa =LIKE. Nhưng việc hỏi liệu một toán tử hay một toán tử khác 'nhanh hơn' trong SQL cũng giống như hỏi 'Cái gì đi nhanh hơn, xe màu đỏ hay xe màu xanh?'. Bạn nên đặt câu hỏi về kích thước động cơ và trọng lượng vechicle, không phải về màu sắc ... Để tiếp cận các câu hỏi về tối ưu hóa bảng quan hệ, nơi cần xem xét là các chỉ mụcbiểu thức của bạn trong mệnh đề WHERE (và các mệnh đề khác, nhưng nó thường bắt đầu bằng WHERE).


5

Một ví dụ cá nhân sử dụng mysql 5.5: Tôi đã có một liên kết bên trong giữa 2 bảng, một trong 3 triệu hàng và một trong 10 nghìn hàng.

Khi sử dụng like trên một chỉ mục như bên dưới (không có ký tự đại diện), mất khoảng 30 giây:

where login like '12345678'

sử dụng 'giải thích' tôi nhận được:

nhập mô tả hình ảnh ở đây

Khi sử dụng dấu '=' trên cùng một truy vấn, mất khoảng 0,1 giây:

where login ='600009'

Sử dụng 'giải thích' tôi nhận được:

nhập mô tả hình ảnh ở đây

Như bạn có thể thấy, liketìm kiếm chỉ mục đã bị hủy hoàn toàn, do đó, truy vấn mất thời gian gấp 300 lần.


Bạn cũng có thể chỉ cần nhìn vào kế hoạch thực hiện để khẳng định điều này
LittleBobbyTables - Au Revoir

cảm ơn @LittleBobbyTables. Sẽ có một cái nhìn vào đó.
Aris

Tôi không biết có phải do phiên bản gần đây của tôi (5.7) hay không, nhưng LIKE không phá vỡ chỉ số duy nhất của tôi ở đây.
Sebas

0

Có thể bạn đang tìm kiếm về Tìm kiếm toàn văn bản .

Ngược lại với tìm kiếm toàn văn bản, vị từ LIKE Transact-SQL chỉ hoạt động trên các mẫu ký tự. Ngoài ra, bạn không thể sử dụng vị từ LIKE để truy vấn dữ liệu nhị phân được định dạng. Hơn nữa, truy vấn LIKE đối với một lượng lớn dữ liệu văn bản không có cấu trúc chậm hơn nhiều so với truy vấn toàn văn bản tương đương với cùng một dữ liệu . Một truy vấn LIKE đối với hàng triệu hàng dữ liệu văn bản có thể mất vài phút để trả về; trong khi truy vấn toàn văn bản có thể chỉ mất vài giây hoặc ít hơn so với cùng một dữ liệu, tùy thuộc vào số hàng được trả về.


-1

Điều đầu tiên trước tiên,

không phải lúc nào họ cũng bình đẳng

    select 'Hello' from dual where 'Hello  ' like 'Hello';

    select 'Hello' from dual where 'Hello  ' =  'Hello';

khi mọi thứ không phải lúc nào cũng bằng nhau, thì việc nói về hiệu suất của họ là không phù hợp.

Nếu bạn đang làm việc trên chuỗi và chỉ biến char, thì bạn có thể nói về hiệu suất. Nhưng không sử dụng like và "=" nói chung có thể hoán đổi cho nhau.

Như bạn đã thấy trong nhiều bài đăng (ở trên và các câu hỏi khác), trong trường hợp chúng bằng nhau, hiệu suất của lượt thích sẽ chậm hơn do đối sánh mẫu (đối chiếu)


Nếu 'Hello 'là một VARCHAR(mặc định) thì bạn đúng, nhưng nếu là một thì CHARbạn không đúng. Truyền nó thành a CHAR(7)và cả hai đều trả về true. Ngoài ra, bạn đang làm cái quái gì khi bạn không nhập TRIMvarchars của mình? (lưu ý: đây là ít nhất là trường hợp trong SQL Server 2008r2)
abluejelly
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.