2009-12-08 27 views
82

thể trùng lặp:
T-SQL WHERE col IN (…)Kích thước tối đa cho truy vấn SQL Server? IN khoản? Có một cách tiếp cận tốt hơn

kích thước tối đa cho một truy vấn SQL Server là gì? (# ký tự)

Kích thước tối đa cho mệnh đề IN? Tôi nghĩ rằng tôi thấy một cái gì đó về Oracle có một giới hạn 1000 mục nhưng bạn có thể nhận được xung quanh này với ANDing 2 INs với nhau. Vấn đề tương tự trong SQL Server?

CẬP NHẬT Vậy điều gì sẽ là phương pháp tốt nhất nếu tôi cần phải thực hiện nói 1000 GUIDs từ một hệ thống khác (Cơ sở dữ liệu không quan hệ) và làm một "JOIN trong mã' so với SQL Server? Có phải nộp danh sách 1000 GUIDs đến một khoản TRÊN? Hoặc là có một kỹ thuật mà làm việc hiệu quả hơn?

tôi đã không kiểm tra này, nhưng tôi tự hỏi nếu tôi có thể nộp GUIDs như một doc XML. Ví dụ

<guids> 
    <guid>809674df-1c22-46eb-bf9a-33dc78beb44a</guid> 
    <guid>257f537f-9c6b-4f14-a90c-ee613b4287f3</guid> 
</guids> 

và sau đó thực hiện một số loại XQuery JOIN chống lại Doc và Bảng. Ít hiệu quả hơn 1000 mục IN khoản?

+1

Có vẻ là một bản sao của: http: // stackoverflow. com/questions/1069415/t-sql-where-col-in – Yishai

+0

Hãy để tôi thêm vào câu hỏi để làm cho câu hỏi trở nên độc đáo hơn. xem tài nguyên cập nhật – BuddyJoe

+1

tôi đã tìm thấy một số ý tưởng - http://www.sommarskog.se/arrays-in-sql-2005.html#InsertMany – BuddyJoe

Trả lời

64

Mỗi lô SQL phải khớp với Batch Size Limit: 65.536 * Kích thước gói mạng.

Ngoài ra, truy vấn của bạn bị giới hạn bởi điều kiện thời gian chạy. Nó thường sẽ chạy ra khỏi kích thước ngăn xếp vì x IN (a, b, c) là gì, nhưng x = a OR x = b HOẶC x = c tạo ra một cây biểu thức tương tự x = a OR (x = b OR (x = c)), vì vậy nó rất sâu với một số lượng lớn OR. SQL 7 sẽ nhấn SO at about 10k values in the IN, nhưng ngày nay ngăn xếp sâu hơn nhiều (vì x64), vì vậy nó có thể đi khá sâu.

Cập nhật

Bạn đã tìm thấy bài viết Erland về chủ đề của truyền danh sách/mảng đến SQL Server. Với SQL 2008, bạn cũng có Table Valued Parameters cho phép bạn chuyển toàn bộ một DataTable như một tham số kiểu bảng duy nhất và tham gia vào nó.

XML và XPath là một giải pháp khả thi:

SELECT ... 
FROM Table 
JOIN (
    SELECT x.value(N'.',N'uniqueidentifier') as guid 
    FROM @values.nodes(N'/guids/guid') t(x)) as guids 
ON Table.guid = guids.guid; 
+0

"kích thước ngăn xếp": đó là lỗi tôi không thể nhớ – gbn

12

mỗi lô, 65536 * Network Packet Size đó là 4k quá 256 MB

Tuy nhiên, IN sẽ dừng lại cách trước đó nhưng nó không phải là chính xác.

Bạn kết thúc với lỗi bộ nhớ nhưng tôi không thể nhớ lỗi chính xác. Một IN lớn sẽ không hiệu quả.

Edit: Remus nhắc nhở tôi: lỗi này là về "ngăn xếp kích thước"

34

Các SQL Server maximums được tiết lộ http://msdn.microsoft.com/en-us/library/ms143432.aspx (đây là phiên bản 2008)

Một SQL Query có thể là một varchar (max) nhưng được hiển thị dưới dạng giới hạn 65.536 * Kích thước gói mạng, nhưng ngay cả khi đó, khả năng bạn truy cập nhiều nhất là 2100 thông số cho mỗi truy vấn. Nếu SQL chọn tham số hóa các giá trị chữ trong mệnh đề in, tôi sẽ nghĩ bạn sẽ đạt đến giới hạn đó trước, nhưng tôi không thử nghiệm nó.

Chỉnh sửa: Kiểm tra nó, ngay cả dưới tham số bắt buộc nó tồn tại - Tôi đã thực hiện một bài kiểm tra nhanh và đã thực thi với 30k mục trong mệnh đề In. (SQL Server 2005)

Tại 100k mục, phải mất một thời gian sau đó giảm với:

Msg 8623, Level 16, State 1, Line 1 Bộ xử lý truy vấn chạy ra khỏi nội lực và không thể tạo kế hoạch truy vấn. Đây là một sự kiện hiếm và chỉ được mong đợi cho các truy vấn hoặc truy vấn cực kỳ phức tạp tham chiếu đến một số lượng lớn các bảng hoặc phân đoạn. Vui lòng đơn giản hóa truy vấn. Nếu bạn tin rằng bạn đã nhận được thông báo này do nhầm lẫn, hãy liên hệ với bộ phận Dịch vụ hỗ trợ khách hàng để biết thêm thông tin.

Vì vậy 30k là có thể, nhưng chỉ vì bạn có thể làm điều đó - không có nghĩa là bạn nên :)

Edit: Tiếp tục do cho câu hỏi bổ sung.

50k đã hoạt động, nhưng 60k bị loại bỏ, vì vậy một nơi nào đó trong đó trên btw thử nghiệm của tôi. Trong điều kiện làm thế nào để làm điều đó tham gia của các giá trị mà không sử dụng một khoản lớn, cá nhân tôi sẽ tạo một bảng tạm thời, chèn các giá trị vào bảng tạm thời đó, chỉ mục nó và sau đó sử dụng nó trong một tham gia, cho nó các cơ hội tốt nhất để tối ưu hóa các kết nối. (Tạo chỉ mục trên bảng tạm thời sẽ tạo số liệu thống kê cho nó, sẽ giúp người tối ưu hóa như một quy tắc chung, mặc dù 1000 GUID sẽ không tìm thấy số liệu thống kê quá hữu ích.)

+1

xem cập nhật. cảm ơn bạn đã thử nghiệm +1 – BuddyJoe

+0

Thật không may những sự kỳ quặc này sẽ diễn ra thường xuyên. Vì vậy, tôi không nghĩ rằng việc lập chỉ mục của bảng tạm thời là có thể. Và để chèn nhanh nhất, bảng chính sẽ được lập chỉ mục bởi một int 'addid' (sẽ không được lập chỉ mục trên GUID). Công cụ này phức tạp hơn tôi tưởng. – BuddyJoe

+1

Bạn đang mạo hiểm tối ưu hóa sớm một chút - bạn cần phải nhận được một số con số cụ thể cứng về các kế hoạch truy vấn cho khối lượng công việc của bạn vì nó sẽ khó để mô hình hóa. Một khi bạn biết các số liệu của các phương pháp khác nhau, bạn có thể lựa chọn, nhưng chèn 1k hàng vào một bảng tạm thời SQL có thể được thực hiện đặc biệt nhanh chóng, nó thực sự phụ thuộc vào cách thức/những gì đang lái nó. – Andrew

7

Bạn có thể tải các GUID vào một bảng đầu sau đó làm một

... WHERE var IN SELECT guid FROM #scratchtable 
+0

Nếu bạn cho rằng bạn sẽ có các truy vấn này sau mỗi hai giây. Tôi tự hỏi làm thế nào bàn cào sẽ giữ lên. – BuddyJoe

+2

Chúng tôi sử dụng kỹ thuật này extensivley trong ứng dụng của chúng tôi và nó có vẻ hoạt động tốt. Tempdb cần phải lớn và chúng tôi thực hiện một số điều chỉnh khi cài đặt - tôi không biết cụ thể về điều đó. Tempdb không bận. – DaveE

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