Remus đã chỉ ra một cách hữu ích rằng độ dài tối đa của VARCHAR
cột ảnh hưởng đến kích thước hàng ước tính và do đó bộ nhớ cấp cho SQL Server.
Tôi đã cố gắng nghiên cứu thêm một chút để mở rộng phần "từ điều này trên tầng thác" trong câu trả lời của anh ấy. Tôi không có một lời giải thích đầy đủ hoặc súc tích, nhưng đây là những gì tôi tìm thấy.
Kịch bản repro
Tôi đã tạo một tập lệnh đầy đủ để tạo một tập dữ liệu giả mà việc tạo chỉ mục mất khoảng 10 lần trên máy của tôi cho VARCHAR(256)
phiên bản. Dữ liệu sử dụng là giống hệt nhau, nhưng bảng đầu tiên sử dụng độ dài tối đa thực tế của 18
, 75
, 9
, 15
, 123
, và 5
, trong khi tất cả các cột sử dụng một chiều dài tối đa của 256
trong bảng thứ hai.
Khóa bảng gốc
Ở đây chúng ta thấy rằng truy vấn ban đầu hoàn thành trong khoảng 20 giây và số lần đọc logic bằng với kích thước bảng của ~1.5GB
(195K trang, 8K mỗi trang).
-- CPU time = 37674 ms, elapsed time = 19206 ms.
-- Table 'testVarchar'. Scan count 9, logical reads 194490, physical reads 0
CREATE CLUSTERED INDEX IX_testVarchar
ON dbo.testVarchar (s1, s2, s3, s4)
WITH (MAXDOP = 8) -- Same as my global MAXDOP, but just being explicit
GO
Khóa bảng VARCHAR (256)
Đối với VARCHAR(256)
bảng, chúng tôi thấy rằng thời gian trôi qua đã tăng lên đáng kể.
Thật thú vị, cả thời gian CPU và số lần đọc logic đều không tăng. Điều này có ý nghĩa khi bảng có cùng dữ liệu, nhưng nó không giải thích được tại sao thời gian trôi qua chậm hơn nhiều.
-- CPU time = 33212 ms, elapsed time = 263134 ms.
-- Table 'testVarchar256'. Scan count 9, logical reads 194491
CREATE CLUSTERED INDEX IX_testVarchar256
ON dbo.testVarchar256 (s1, s2, s3, s4)
WITH (MAXDOP = 8) -- Same as my global MAXDOP, but just being explicit
GO
Số liệu thống kê I / O và chờ đợi: bản gốc
Nếu chúng ta nắm bắt chi tiết hơn một chút (sử dụng p_perfMon, một thủ tục mà tôi đã viết ), chúng ta có thể thấy rằng phần lớn I / O được thực hiện trên LOG
tệp. Chúng tôi thấy số lượng I / O tương đối khiêm tốn trên thực tế ROWS
(tệp dữ liệu chính) và loại chờ chính là LATCH_EX
, biểu thị sự tranh chấp trong bộ nhớ.
Chúng ta cũng có thể thấy rằng đĩa quay của tôi nằm ở đâu đó giữa "xấu" và "cực kỳ tệ", theo Paul Randal :)
Số liệu thống kê I / O và chờ: VARCHAR (256)
Đối với VARCHAR(256)
phiên bản, số liệu thống kê I / O và chờ hoàn toàn khác nhau! Ở đây, chúng ta thấy sự gia tăng rất lớn của I / O trên tệp dữ liệu ( ROWS
) và thời gian ngừng hoạt động khiến Paul Randal chỉ đơn giản nói "WOW!".
Không có gì đáng ngạc nhiên khi loại chờ đợi số 1 bây giờ IO_COMPLETION
. Nhưng tại sao I / O được tạo ra nhiều như vậy?
Gói truy vấn thực tế: VARCHAR (256)
Từ kế hoạch truy vấn, chúng ta có thể thấy rằng Sort
toán tử có một sự cố tràn đệ quy (sâu 5 cấp!) Trong VARCHAR(256)
phiên bản của truy vấn. (Không có sự cố tràn nào trong phiên bản gốc.)
Tiến trình truy vấn trực tiếp: VARCHAR (256)
Chúng tôi có thể sử dụng sys.dm_exec_query_profiles để xem tiến trình truy vấn trực tiếp trong SQL 2014+ . Trong phiên bản gốc, toàn bộ Table Scan
và Sort
được xử lý mà không có sự cố tràn ( spill_page_count
vẫn còn 0
trong suốt).
VARCHAR(256)
Tuy nhiên, trong phiên bản, chúng ta có thể thấy rằng sự cố tràn trang nhanh chóng tích lũy cho người Sort
vận hành. Dưới đây là ảnh chụp tiến trình truy vấn ngay trước khi truy vấn hoàn tất. Dữ liệu ở đây được tổng hợp trên tất cả các chủ đề.
Nếu tôi đào sâu vào từng luồng riêng lẻ, tôi thấy rằng 2 luồng hoàn thành sắp xếp trong vòng khoảng 5 giây (tổng thể @ 20 giây, sau 15 giây dành cho việc quét bảng). Nếu tất cả các luồng tiến triển với tốc độ này, việc VARCHAR(256)
tạo chỉ mục sẽ hoàn thành gần như cùng lúc với bảng gốc.
Tuy nhiên, 6 luồng còn lại tiến triển với tốc độ chậm hơn nhiều. Điều này có thể là do cách phân bổ bộ nhớ và cách các luồng được giữ bởi I / O khi chúng tràn dữ liệu. Tôi không biết chắc chắn mặc dù.
Bạn có thể làm gì?
Có một số điều bạn có thể cân nhắc thử:
- Làm việc với nhà cung cấp để quay lại phiên bản trước. Nếu điều đó là không thể, hãy để nhà cung cấp mà bạn không hài lòng với thay đổi này để họ có thể xem xét hoàn nguyên nó trong phiên bản tương lai.
- Khi thêm chỉ số của bạn, hãy xem xét sử dụng
OPTION (MAXDOP X)
ở đâu X
là một con số thấp hơn so với thiết lập máy chủ cấp hiện tại của bạn. Khi tôi sử dụng OPTION (MAXDOP 2)
trên tập dữ liệu cụ thể này trên máy của mình, VARCHAR(256)
phiên bản đã hoàn thành 25 seconds
(so với 3-4 phút với 8 luồng!). Có thể hành vi đổ tràn bị làm trầm trọng thêm bởi tính song song cao hơn.
- Nếu đầu tư phần cứng bổ sung là một khả năng, hãy lập hồ sơ I / O (nút cổ chai có khả năng) trên hệ thống của bạn và xem xét sử dụng ổ SSD để giảm độ trễ của I / O do sự cố tràn.
đọc thêm
Paul White có một bài đăng blog tốt đẹp về các loại nội bộ của SQL Server có thể được quan tâm. Nó nói một chút về việc đổ, xiên chuỗi và cấp phát bộ nhớ cho các loại song song.