Database
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Database

Xác định và Khắc phục Sự cố Hiệu suất Hồ sơ Chuyển tiếp

Trước khi giải quyết vấn đề hiệu suất Bản ghi chuyển tiếp và giải quyết nó, chúng ta cần xem lại cấu trúc của bảng SQL Server.

Tổng quan về cấu trúc bảng

Trong SQL Server, đơn vị cơ bản của bộ nhớ dữ liệu là Trang 8 KB . Mỗi trang bắt đầu với một tiêu đề 96 byte lưu trữ thông tin hệ thống về trang đó. Sau đó, các hàng của bảng sẽ được lưu trữ trên các trang dữ liệu theo thứ tự sau tiêu đề. Ở cuối trang, bảng bù hàng, chứa một mục nhập cho mỗi hàng, sẽ được lưu trữ đối diện với trình tự của các hàng trong trang. Mục nhập bù đắp hàng này cho biết byte đầu tiên của hàng đó nằm cách đầu trang bao xa.

SQL Server cung cấp cho chúng ta hai loại bảng, dựa trên cấu trúc của bảng đó. Nhóm bảng lưu trữ và sắp xếp dữ liệu trong các trang dữ liệu dựa trên các giá trị cột hoặc cột chỉ mục Clustered được xác định trước. Ngoài ra, các trang dữ liệu trong bảng Clustered được sắp xếp và liên kết với nhau trong một danh sách được liên kết dựa trên các giá trị khóa của chỉ mục Clustered. Cây B cấu trúc của chỉ mục Clustered cung cấp một phương pháp truy cập dữ liệu nhanh chóng dựa trên các giá trị khóa của chỉ mục Clustered. Nếu một hàng mới được chèn hoặc một giá trị khóa hiện có được cập nhật trong bảng Clustered, SQL Server sẽ lưu trữ giá trị mới ở vị trí logic chính xác phù hợp với kích thước hàng được chèn mà không phá vỡ tiêu chí sắp xếp. Nếu giá trị được chèn hoặc cập nhật lớn hơn không gian có sẵn trong trang dữ liệu, trang sẽ được chia thành hai trang để phù hợp với giá trị mới.

Loại bảng thứ hai là Heap bảng, trong đó dữ liệu không được sắp xếp trong các trang dữ liệu theo bất kỳ thứ tự nào và các trang không được liên kết với nhau, vì không có chỉ mục Clustered được xác định trên bảng đó, để thực thi bất kỳ tiêu chí sắp xếp nào. Theo dõi các trang không được sắp xếp theo bất kỳ tiêu chí thứ tự nào hoặc được liên kết với nhau trong bảng đống không phải là một nhiệm vụ dễ dàng. Để đơn giản hóa quy trình theo dõi phân bổ trang trong bảng heap, SQL Server sử dụng Bản đồ phân bổ chỉ mục (IAM), kết nối logic duy nhất giữa các trang dữ liệu trong bảng heap, bằng cách giữ một mục nhập cho mỗi trang dữ liệu trong bảng hoặc chỉ mục trong bảng IAM. Để truy xuất bất kỳ dữ liệu nào từ bảng heap, SQL Server Engine quét IAM để xác định phạm vi, phạm vi này tạo thành 8 trang lưu trữ dữ liệu được yêu cầu.

Vấn đề về bản ghi đã chuyển tiếp

Nếu một hàng mới được chèn vào bảng heap, SQL Server Engine sẽ quét Dung lượng trống của trang (PFS) các trang để theo dõi trạng thái phân bổ và sử dụng không gian trên mỗi trang dữ liệu để tìm vị trí khả dụng đầu tiên trong các trang dữ liệu phù hợp với kích thước hàng được chèn. Sau đó, hàng sẽ được thêm vào trang đã chọn. Nếu giá trị được chèn lớn hơn không gian có sẵn trong các trang dữ liệu, một trang mới sẽ được thêm vào bảng đó để có thể chèn giá trị mới.

Mặt khác, nếu dữ liệu hiện có trong bảng heap được sửa đổi, ví dụ:chúng tôi đã cập nhật một chuỗi có độ dài thay đổi với kích thước dữ liệu lớn hơn và không gian hiện tại không phù hợp với dữ liệu mới, dữ liệu sẽ được chuyển sang một vật lý khác. vị trí và Bản ghi được chuyển tiếp sẽ được chèn vào bảng heap ở vị trí dữ liệu ban đầu, để trỏ đến vị trí mới của dữ liệu đó và để đơn giản hóa vị trí dữ liệu theo dõi. Vị trí dữ liệu mới cũng chứa một con trỏ trỏ đến con trỏ chuyển tiếp để giữ cho nó được cập nhật trong trường hợp di chuyển dữ liệu từ vị trí mới và để ngăn chặn chuỗi con trỏ chuyển tiếp dài hoặc xóa nó. Điều này cũng có thể dẫn đến việc xóa bản ghi chuyển tiếp.

Mặc dù phương pháp chuyển hướng Bản ghi chuyển tiếp làm giảm nhu cầu về hoạt động xây dựng lại bảng sử dụng nhiều tài nguyên và các chỉ mục không phân cụm để cập nhật địa chỉ dữ liệu mỗi khi vị trí của dữ liệu được thay đổi, nó cũng tăng gấp đôi số lần đọc cần thiết để truy xuất dữ liệu. SQL Server sẽ truy cập vị trí cũ trước tiên, nơi nó sẽ tìm thấy Bản ghi được chuyển tiếp chuyển hướng nó đến vị trí dữ liệu mới. Sau đó, nó sẽ đọc dữ liệu được yêu cầu, thực hiện thao tác đọc hai lần. Ngoài ra, vấn đề Bản ghi chuyển tiếp dẫn đến việc thay đổi dữ liệu tuần tự được đọc thành dữ liệu ngẫu nhiên đọc ảnh hưởng tiêu cực đến hiệu suất hoạt động truy xuất dữ liệu theo thời gian.

Hãy để chúng tôi tạo heap ForwardRecordDemo sau sử dụng câu lệnh T-SQL CREATE TABLE TABLE bên dưới:

CREATE TABLE ForwardRecordDemo
( ID INT IDENTITY (1,1),
  Emp_Name NVARCHAR (50),
  Emp_BirthDate DATETIME,
  Emp_Salary INT 
)

Sau đó, điền vào bảng đó với các bản ghi 3K cho mục đích thử nghiệm, sử dụng câu lệnh INSERT INTO T-SQL bên dưới:

INSERT INTO ForwardRecordDemo VALUES ('John','2000-05-05',500)
GO 1000
INSERT INTO ForwardRecordDemo VALUES ('Zaid','1999-01-07',700)
GO 1000
INSERT INTO ForwardRecordDemo VALUES ('Frank','1988-07-04',900)
GO 1000

Xác định Vấn đề Hồ sơ Chuyển tiếp

Có thể xem thông tin về loại bảng và số trang được sử dụng trong khi lưu trữ dữ liệu bảng, cũng như tỷ lệ phân mảnh chỉ mục và số Bản ghi được chuyển tiếp cho một bảng cụ thể bằng cách truy vấn sys.dm_db_index_physical_stats chức năng quản lý động của hệ thống và bằng cách chuyển đến DETAILED chế độ trả về số lượng Bản ghi chuyển tiếp. Để thực hiện việc này, hãy sử dụng tập lệnh T-SQL bên dưới:

SELECT
    OBJECT_NAME(PhysSta.object_id) as DBTableName,
    PhysSta.index_type_desc,
    PhysSta.avg_fragmentation_in_percent,
    PhysSta.forwarded_record_count,
    PhysSta.page_count
FROM sys.dm_db_index_physical_stats (DB_ID(), DEFAULT, DEFAULT, DEFAULT, 'DETAILED') AS PhysSta
WHERE OBJECT_NAME(PhysSta.object_id) = 'ForwardRecordDemo' AND forwarded_record_count is NOT NULL

Như bạn có thể thấy từ kết quả truy vấn, bảng trước đó là bảng heap không có chỉ mục Clustered được tạo trên đó để sắp xếp dữ liệu trong các trang và liên kết các trang với nhau. 3K hàng được chèn vào bảng được gán cho 15 các trang dữ liệu, không có bản ghi được chuyển tiếp và tỷ lệ phần trăm phân mảnh bằng không, như được hiển thị trong kết quả bên dưới:

Khi bạn xác định kiểu dữ liệu của cột là VARCHAR hoặc NVARCHAR, giá trị được chỉ định trong định nghĩa kiểu dữ liệu là kích thước tối đa được phép cho chuỗi đó mà không cần dự trữ đầy đủ số lượng đó trong khi lưu các giá trị vào các trang dữ liệu. Ví dụ: John tên nhân viên được chèn vào bảng đó sẽ chỉ dành 8 byte trong số 100 byte tối đa cho cột đó, có tính đến việc lưu chuỗi NVARCHAR sẽ nhân đôi số byte cần thiết cho cột VARCHAR, như được hiển thị trong DATALENGTH > kết quả hàm bên dưới:

Nếu bạn muốn cập nhật giá trị của cột Emp_Name để bao gồm tên đầy đủ của nhân viên John, hãy sử dụng câu lệnh UPDATE bên dưới:

UPDATE ForwardRecordDemo SET Emp_Name='John David Micheal'
WHERE Emp_Name='John'

Kiểm tra độ dài của cột được cập nhật bằng cách sử dụng DATALENGTH hàm số. Bạn sẽ thấy rằng độ dài của cột Emp_Name trong các hàng được cập nhật đã được mở rộng thêm 28 byte trên mỗi cột, khoảng 3,5 các trang dữ liệu bổ sung vào bảng đó, như được hiển thị trong kết quả bên dưới:

Sau đó, kiểm tra số lượng Bản ghi được chuyển tiếp sau thao tác cập nhật bằng cách truy vấn chức năng quản lý động hệ thống sys.dm_db_index_physical_stats. Để thực hiện việc này, hãy sử dụng tập lệnh T-SQL bên dưới:

SELECT
    OBJECT_NAME(PhysSta.object_id) as DBTableName,
    PhysSta.index_type_desc,
    PhysSta.avg_fragmentation_in_percent,
    PhysSta.forwarded_record_count,
    PhysSta.page_count
FROM sys.dm_db_index_physical_stats (DB_ID(), DEFAULT, DEFAULT, DEFAULT, 'DETAILED') AS PhysSta
WHERE OBJECT_NAME(PhysSta.object_id) = 'ForwardRecordDemo' AND forwarded_record_count is NOT NULL

Như bạn có thể thấy, việc cập nhật cột Emp_Name trên 1K bản ghi có giá trị chuỗi lớn hơn, mà không thêm bất kỳ bản ghi mới nào, sẽ chỉ định thêm 5 các trang của bảng đó, thay vì 3,5 trang như mong đợi trước đây. Điều này sẽ xảy ra do tạo 484 các bản ghi được chuyển tiếp để trỏ đến các vị trí mới của dữ liệu đã di chuyển. Điều này có thể khiến bảng là 33% bị phân mảnh, như được hiển thị rõ ràng bên dưới:

Một lần nữa, nếu bạn quản lý cập nhật giá trị của cột Emp_Name để bao gồm tên đầy đủ của nhân viên Zaid, hãy sử dụng câu lệnh UPDATE bên dưới:

UPDATE ForwardRecordDemo SET Emp_Name='Zaid Fuad Zreeq'
WHERE Emp_Name='Zaid'

Kiểm tra độ dài của cột được cập nhật bằng cách sử dụng DATALENGTH hàm số. Bạn sẽ thấy rằng độ dài của cột Emp_Name trong các hàng cập nhật được mở rộng thêm 22 byte trên mỗi cột, khoảng 2,7 các trang dữ liệu bổ sung được thêm vào bảng đó, như được hiển thị trong kết quả bên dưới:

Kiểm tra số lượng bản ghi được chuyển tiếp sau khi thực hiện thao tác cập nhật. Bạn có thể thực hiện việc này bằng cách truy vấn hàm quản lý động hệ thống sys.dm_db_index_physical_stats bằng cách sử dụng cùng một tập lệnh T-SQL bên dưới:

SELECT
    OBJECT_NAME(PhysSta.object_id) as DBTableName,
    PhysSta.index_type_desc,
    PhysSta.avg_fragmentation_in_percent,
    PhysSta.forwarded_record_count,
    PhysSta.page_count
FROM sys.dm_db_index_physical_stats (DB_ID(), DEFAULT, DEFAULT, DEFAULT, 'DETAILED') AS PhysSta
WHERE OBJECT_NAME(PhysSta.object_id) = 'ForwardRecordDemo' AND forwarded_record_count is NOT NULL

Kết quả sẽ cho bạn thấy rằng việc cập nhật cột Emp_Name trên các bản ghi 1K khác có giá trị chuỗi lớn hơn mà không chèn bất kỳ hàng mới nào sẽ chỉ định một 4 khác các trang của bảng đó, thay vì 2,7 trang như mong đợi. Điều này sẽ xảy ra do tạo thêm 417 các bản ghi được chuyển tiếp để trỏ đến các vị trí mới của dữ liệu đã di chuyển và giữ nguyên 33% phần trăm phân mảnh, như được hiển thị bên dưới:

Khắc phục sự cố bản ghi được chuyển tiếp

Cách đơn giản nhất để khắc phục sự cố Bản ghi chuyển tiếp là ước tính độ dài tối đa của chuỗi sẽ được lưu trữ trong cột và chỉ định nó bằng cách sử dụng độ dài cố định kiểu dữ liệu cho cột đó thay vì sử dụng kiểu dữ liệu có độ dài thay đổi. Cách vĩnh viễn tối ưu để khắc phục sự cố Bản ghi được chuyển tiếp là thêm Chỉ mục được phân nhóm vào bảng đó. Bằng cách này, bảng sẽ được chuyển đổi hoàn toàn thành bảng Clustered, được sắp xếp dựa trên các giá trị khóa của chỉ mục Clustered. Nó sẽ kiểm soát thứ tự của dữ liệu hiện có, dữ liệu mới được chèn và cập nhật không phù hợp với không gian có sẵn hiện tại trong trang dữ liệu, như được mô tả trước đây trong phần giới thiệu của bài viết này.

Nếu việc thêm chỉ mục Clustered vào bảng đó không phải là một tùy chọn cho các yêu cầu cụ thể, chẳng hạn như bảng dàn hoặc bảng ETL, bạn có thể khắc phục tạm thời vấn đề Bản ghi được chuyển tiếp bằng cách theo dõi Bản ghi được chuyển tiếp và xây dựng lại bảng heap để xóa nó, điều đó sẽ cũng cập nhật tất cả các chỉ mục Không phân cụm trên bảng heap đó. Chức năng xây dựng lại bảng heap được giới thiệu trong SQL Server 2008, bằng cách sử dụng ALTER TABLE… REBUILD Lệnh T-SQL.

Để xem tác động về hiệu suất của Bản ghi được chuyển tiếp đối với các truy vấn truy xuất dữ liệu, chúng ta hãy chạy truy vấn SELECT thực hiện tìm kiếm dựa trên các giá trị của cột Emp_Nameю Tuy nhiên, trước khi thực hiện truy vấn, hãy bật thống kê TIME và IO:

SET STATISTICS TIME ON
SET STATISTICS IO ON

SELECT * FROM ForwardRecordDemo WHERE Emp_Name like 'John%'

Kết quả là bạn sẽ thấy rằng 925 các thao tác đọc logic được thực hiện để truy xuất dữ liệu được yêu cầu trong vòng 84ms như hình dưới đây:

Để xây dựng lại bảng heap nhằm loại bỏ tất cả các Bản ghi được Chuyển tiếp, hãy sử dụng lệnh ALTER TABLE… REBUILD:

ALTER TABLE ForwardRecordDemo REBUILD;

Chạy lại cùng một câu lệnh SELECT:

SELECT * FROM ForwardRecordDemo WHERE Emp_Name like 'John%'

Thống kê TIME và IO sẽ cho bạn thấy rằng chỉ 21 các thao tác đọc logic so với 925 Các thao tác đọc logic với Bản ghi chuyển tiếp được bao gồm được thực hiện để truy xuất dữ liệu được yêu cầu trong vòng 79ms :

Để kiểm tra số lượng bản ghi được chuyển tiếp sau khi tạo lại bảng heap, hãy chạy chức năng quản lý động hệ thống sys.dm_db_index_physical_stats, sử dụng cùng một tập lệnh T-SQL bên dưới:

SELECT
    OBJECT_NAME(PhysSta.object_id) as DBTableName,
    PhysSta.index_type_desc,
    PhysSta.avg_fragmentation_in_percent,
    PhysSta.forwarded_record_count,
    PhysSta.page_count
FROM sys.dm_db_index_physical_stats (DB_ID(), DEFAULT, DEFAULT, DEFAULT, 'DETAILED') AS PhysSta
WHERE OBJECT_NAME(PhysSta.object_id) = 'ForwardRecordDemo' AND forwarded_record_count is NOT NULL

Bạn sẽ thấy rằng chỉ có 21 các trang, với 3 trước đó các trang được sử dụng cho Bản ghi được chuyển tiếp, được gán cho bảng đó để lưu trữ dữ liệu, tương tự như kết quả ước tính mà chúng tôi nhận được trong quá trình chèn và cập nhật dữ liệu (15 + 3,5 + 2,7). Sau khi xây dựng lại bảng đống, tất cả Bản ghi được chuyển tiếp sẽ bị xóa ngay bây giờ. Kết quả là chúng ta có một bảng không có sự phân mảnh:


Vấn đề Bản ghi chuyển tiếp là một vấn đề hiệu suất quan trọng mà quản trị viên cơ sở dữ liệu nên xem xét khi lập kế hoạch cho bảo trì bảng đống. Các kết quả trước đó được truy xuất từ ​​bảng thử nghiệm của chúng tôi chỉ chứa 3K bản ghi. Bạn có thể tưởng tượng số lượng trang sẽ bị lãng phí bởi Bản ghi được chuyển tiếp và sự suy giảm hiệu suất I / O do phải đọc một số lượng lớn Bản ghi được chuyển tiếp khi đọc từ các bảng lớn!

Tài liệu tham khảo:

  • Hướng dẫn về Kiến trúc của Trang và Mức độ
  • dm_db_index_physical_stats (Transact-SQL)
  • BẢNG ALTER (Transact-SQL)
  • Biết về 'Bản ghi được chuyển tiếp' có thể giúp chẩn đoán các vấn đề khó tìm về hiệu suất

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Trình điều khiển ODBC Easysoft và Thư viện ODBCINST

  2. Tạo môi trường thử nghiệm từ kho sản xuất

  3. Bắt đầu Điều chỉnh Hiệu suất trong Cơ sở dữ liệu Azure SQL

  4. Không gian bảng SYSMGMTDATA là ĐẦY ĐỦ trong Kho lưu trữ Quản lý Cơ sở Hạ tầng Lưới (MGMTDB)

  5. SQL là gì?