Như bất kỳ DBA sản xuất kỳ cựu nào đều biết, bạn thường phải chịu áp lực đáng kể trong việc chẩn đoán và giảm bớt các vấn đề về hiệu suất cơ sở dữ liệu càng nhanh càng tốt. Dưới đây là ba điều bạn có thể tận dụng, tùy thuộc vào khối lượng công việc và cơ sở hạ tầng của bạn, để có tác động tích cực đáng chú ý đến hiệu suất cơ sở dữ liệu của bạn.
Điều chỉnh chỉ mục cửa hàng hàng cơ bản
Hầu hết các phiên bản SQL Server mà tôi gặp phải trong sự nghiệp của mình đều có một số cơ hội điều chỉnh chỉ mục lưu trữ hàng tương đối dễ dàng. Một điều thú vị về điều chỉnh chỉ mục lưu trữ hàng là nó thường nằm dưới sự kiểm soát trực tiếp của bạn như một DBA, đặc biệt là so với điều chỉnh truy vấn hoặc thủ tục được lưu trữ, thường nằm dưới sự kiểm soát của các nhà phát triển hoặc nhà cung cấp 3 bên.
Một số DBA miễn cưỡng thực hiện bất kỳ điều chỉnh chỉ mục nào (đặc biệt là trên cơ sở dữ liệu của 3 bên) vì họ lo lắng về việc phá vỡ điều gì đó hoặc gây nguy hiểm cho sự hỗ trợ của nhà cung cấp đối với cơ sở dữ liệu hoặc ứng dụng. Rõ ràng, bạn cần phải cẩn thận hơn với cơ sở dữ liệu của 3 bên và cố gắng liên hệ với nhà cung cấp trước khi tự mình thực hiện bất kỳ thay đổi chỉ mục nào, nhưng trong một số tình huống, bạn có thể không có giải pháp thay thế khả thi nào khác (ngoài việc ném phần cứng và bộ nhớ nhanh hơn vào vấn đề ).
Bạn có thể chạy một vài truy vấn chính từ Truy vấn thông tin chẩn đoán SQL Server của tôi để có ý tưởng hay nếu bạn có thể có một số cơ hội điều chỉnh chỉ mục dễ dàng trên phiên bản hoặc cơ sở dữ liệu của mình. Bạn nên đề phòng các yêu cầu lập chỉ mục bị thiếu, cảnh báo chỉ mục bị thiếu, các chỉ mục không phân nhóm chưa được sử dụng hoặc không được sử dụng và các cơ hội nén dữ liệu có thể có.
Cần một số kinh nghiệm, khả năng phán đoán tốt và kiến thức về khối lượng công việc của bạn để thực hiện điều chỉnh chỉ mục thích hợp. Việc mọi người điều chỉnh chỉ mục không chính xác là điều quá phổ biến, bằng cách hấp tấp thực hiện nhiều thay đổi chỉ mục mà không thực hiện phân tích thích hợp.
Dưới đây là một số truy vấn mà tôi muốn sử dụng, ở cấp cơ sở dữ liệu:
-- Missing Indexes for current database by Index Advantage (Query 1) (Missing Indexes) SELECT DISTINCT CONVERT(decimal(18,2), user_seeks * avg_total_user_cost * (avg_user_impact * 0.01)) AS [index_advantage], migs.last_user_seek, mid.[statement] AS [Database.Schema.Table], mid.equality_columns, mid.inequality_columns, mid.included_columns, migs.unique_compiles, migs.user_seeks, migs.avg_total_user_cost, migs.avg_user_impact, OBJECT_NAME(mid.[object_id]) AS [Table Name], p.rows AS [Table Rows] FROM sys.dm_db_missing_index_group_stats AS migs WITH (NOLOCK) INNER JOIN sys.dm_db_missing_index_groups AS mig WITH (NOLOCK) ON migs.group_handle = mig.index_group_handle INNER JOIN sys.dm_db_missing_index_details AS mid WITH (NOLOCK) ON mig.index_handle = mid.index_handle INNER JOIN sys.partitions AS p WITH (NOLOCK) ON p.[object_id] = mid.[object_id] WHERE mid.database_id = DB_ID() AND p.index_id < 2 ORDER BY index_advantage DESC OPTION (RECOMPILE); ------ -- Look at index advantage, last user seek time, number of user seeks to help determine source and importance -- SQL Server is overly eager to add included columns, so beware -- Do not just blindly add indexes that show up from this query!!! -- Find missing index warnings for cached plans in the current database (Query 2) (Missing Index Warnings) -- Note: This query could take some time on a busy instance SELECT TOP(25) OBJECT_NAME(objectid) AS [ObjectName], cp.objtype, cp.usecounts, cp.size_in_bytes, query_plan FROM sys.dm_exec_cached_plans AS cp WITH (NOLOCK) CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp WHERE CAST(query_plan AS NVARCHAR(MAX)) LIKE N'%MissingIndex%' AND dbid = DB_ID() ORDER BY cp.usecounts DESC OPTION (RECOMPILE); ------ -- Helps you connect missing indexes to specific stored procedures or queries -- This can help you decide whether to add them or not -- Possible Bad NC Indexes (writes >= reads) (Query 3) (Bad NC Indexes) SELECT OBJECT_NAME(s.[object_id]) AS [Table Name], i.name AS [Index Name], i.index_id, i.is_disabled, i.is_hypothetical, i.has_filter, i.fill_factor, s.user_updates AS [Total Writes], s.user_seeks + s.user_scans + s.user_lookups AS [Total Reads], s.user_updates - (s.user_seeks + s.user_scans + s.user_lookups) AS [Difference] FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK) INNER JOIN sys.indexes AS i WITH (NOLOCK) ON s.[object_id] = i.[object_id] AND i.index_id = s.index_id WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1 AND s.database_id = DB_ID() AND s.user_updates > (s.user_seeks + s.user_scans + s.user_lookups) AND i.index_id > 1 AND i.[type_desc] = N'NONCLUSTERED' AND i.is_primary_key = 0 AND i.is_unique_constraint = 0 AND i.is_unique = 0 ORDER BY [Difference] DESC, [Total Writes] DESC, [Total Reads] ASC OPTION (RECOMPILE); ------ -- Look for indexes with high numbers of writes and zero or very low numbers of reads -- Consider your complete workload, and how long your instance has been running -- Investigate further before dropping an index! -- Breaks down buffers used by current database by object (table, index) in the buffer cache (Query 4) (Buffer Usage) -- Note: This query could take some time on a busy instance SELECT OBJECT_NAME(p.[object_id]) AS [Object Name], p.index_id, CAST(COUNT(*)/128.0 AS DECIMAL(10, 2)) AS [Buffer size(MB)], COUNT(*) AS [BufferCount], p.[Rows] AS [Row Count], p.data_compression_desc AS [Compression Type] FROM sys.allocation_units AS a WITH (NOLOCK) INNER JOIN sys.dm_os_buffer_descriptors AS b WITH (NOLOCK) ON a.allocation_unit_id = b.allocation_unit_id INNER JOIN sys.partitions AS p WITH (NOLOCK) ON a.container_id = p.hobt_id WHERE b.database_id = CONVERT(int, DB_ID()) AND p.[object_id] > 100 AND OBJECT_NAME(p.[object_id]) NOT LIKE N'plan_%' AND OBJECT_NAME(p.[object_id]) NOT LIKE N'sys%' AND OBJECT_NAME(p.[object_id]) NOT LIKE N'xml_index_nodes%' GROUP BY p.[object_id], p.index_id, p.data_compression_desc, p.[Rows] ORDER BY [BufferCount] DESC OPTION (RECOMPILE); ------ -- Tells you what tables and indexes are using the most memory in the buffer cache -- It can help identify possible candidates for data compression
Sử dụng Độ bền bị trì hoãn
Tính năng độ bền bị trì hoãn đã được thêm vào sản phẩm trong SQL Server 2014, vì vậy nó đã khả dụng được một thời gian. Cam kết giao dịch lâu bền bị trì hoãn là không đồng bộ và báo cáo cam kết giao dịch là thành công trước đó các bản ghi nhật ký cho giao dịch thực sự được ghi vào hệ thống con lưu trữ. Các giao dịch lâu bền bị trì hoãn không thực sự trở nên lâu bền cho đến khi các mục nhập nhật ký giao dịch được chuyển vào đĩa.
Tính năng này có sẵn trong tất cả các phiên bản của SQL Server. Mặc dù vậy, tôi hiếm khi thấy nó được sử dụng khi tôi xem xét cơ sở dữ liệu khách hàng. Độ bền bị trì hoãn mở ra khả năng mất một số dữ liệu, lên đến toàn bộ bộ đệm nhật ký trong trường hợp xấu nhất (như Paul Randal giải thích ở đây), vì vậy nó chắc chắn không thích hợp cho tình huống RPO mà hoàn toàn không chấp nhận được việc mất dữ liệu.
Độ bền trì hoãn làm giảm độ trễ của giao dịch vì nó không đợi IO nhật ký hoàn thành và trả lại quyền kiểm soát cho máy khách, đồng thời nó cũng làm giảm sự khóa và tranh chấp đĩa đối với các giao dịch đồng thời. Hai lợi ích này thường có thể có tác động rất tích cực đến hiệu suất truy vấn và ứng dụng của bạn với khối lượng công việc rất nặng thích hợp.
Độ bền bị trễ thường sẽ giúp ích nhiều nhất cho khối lượng công việc loại OLTP nặng có các giao dịch ghi rất thường xuyên, nhỏ, trong đó bạn đang thấy độ trễ ghi ở cấp độ tệp cao từ sys.dm_io_virtual_file_stats trên tệp nhật ký giao dịch và / hoặc bạn đang thấy WRITELOG cao chờ đợi từ hệ thống. dm_os_wait_stats.
Bạn có thể dễ dàng buộc SQL Server 2014 trở lên sử dụng độ bền chậm cho tất cả các giao dịch (không có thay đổi mã) bằng cách chạy lệnh sau:
ALTER DATABASE AdventureWorks2014 SET DELAYED_DURABILITY = FORCED;
Tôi đã có những khách hàng lập trình bật và tắt độ bền bị trì hoãn vào các thời điểm khác nhau trong ngày (chẳng hạn như trong ETL theo lịch trình hoặc hoạt động bảo trì). Tôi cũng đã có những khách hàng luôn sử dụng độ bền trì hoãn vì họ có khối lượng công việc thích hợp và khả năng chấp nhận rủi ro mất dữ liệu.
Cuối cùng, tôi đã có những khách hàng không bao giờ cân nhắc việc sử dụng độ bền bị trì hoãn hoặc đơn giản là không cần nó với khối lượng công việc của họ. Nếu bạn nghi ngờ rằng khối lượng công việc của mình có thể được hưởng lợi từ việc sử dụng độ bền chậm, nhưng bạn lo lắng về khả năng mất dữ liệu, thì bạn có thể xem xét các lựa chọn thay thế khác.
Một giải pháp thay thế là tính năng đệm nhật ký liên tục trong SQL Server 2016 SP1, nơi bạn có thể tạo tệp nhật ký giao dịch thứ hai, 20MB trên khối lượng lưu trữ ở chế độ truy cập trực tiếp (DAX) được lưu trữ trên thiết bị bộ nhớ liên tục NV-DIMM. Tệp nhật ký giao dịch bổ sung này được sử dụng để lưu vào bộ nhớ cache phần đuôi của nhật ký, với quyền truy cập cấp byte bỏ qua ngăn xếp lưu trữ cấp khối thông thường.
Nếu bạn nghĩ rằng khối lượng công việc của mình có thể được hưởng lợi từ việc sử dụng tính năng bộ đệm nhật ký liên tục, bạn có thể thử nghiệm tạm thời sử dụng độ bền bị trì hoãn để xem liệu có lợi ích hiệu suất thực sự với khối lượng công việc của bạn hay không trước khi chi tiền cho bộ nhớ liên tục NV-DIMM mà bạn sẽ cần sử dụng tính năng đệm nhật ký liên tục.
Di chuyển tempdb sang Bộ nhớ Intel Optane DC P4800X
Tôi đã thành công rực rỡ với một số khách hàng gần đây đã chuyển tệp cơ sở dữ liệu tempdb của họ từ một số loại lưu trữ khác sang ổ đĩa logic được hỗ trợ bởi một vài thẻ lưu trữ Intel Optane DC P4800X PCIe NVMe (trong mảng RAID 1 phần mềm).
Các thẻ lưu trữ này có các mức dung lượng 375GB, 750GB và 1.5TB (mặc dù dung lượng 1.5TB là thương hiệu mới và vẫn khó tìm). Chúng có độ trễ cực thấp (thấp hơn nhiều so với bất kỳ loại lưu trữ flash NAND nào), hiệu suất I / O ngẫu nhiên tuyệt vời ở độ sâu hàng đợi thấp (tốt hơn nhiều so với lưu trữ flash NAND), với thời gian phản hồi đọc nhất quán trong khối lượng công việc ghi rất nặng.
Chúng cũng có độ bền ghi cao hơn so với bộ lưu trữ flash NAND dành cho doanh nghiệp “chuyên sâu” và hiệu suất của chúng không suy giảm khi chúng gần đầy. Những đặc điểm này làm cho các thẻ này cực kỳ phù hợp với nhiều khối lượng công việc tempdb nặng, khối lượng công việc OLTP đặc biệt nặng và các tình huống mà bạn đang sử dụng RCSI trong cơ sở dữ liệu người dùng của mình (đặt khối lượng công việc lưu trữ phiên bản kết quả trên tempdb).
Rất thường thấy độ trễ ghi ở cấp độ tệp cao trên các tệp dữ liệu tempdb từ sys.dm_io_virtual_file_stats DMV, vì vậy việc di chuyển tệp dữ liệu tempdb của bạn sang bộ nhớ Optane là một cách để giải quyết trực tiếp vấn đề đó, có thể nhanh hơn và dễ dàng hơn so với thông thường điều chỉnh khối lượng công việc.
Một cách sử dụng khác có thể có đối với thẻ lưu trữ Optane là làm nơi lưu trữ (các) tệp nhật ký giao dịch của bạn. Bạn cũng có thể sử dụng lưu trữ Optane với các phiên bản cũ của SQL Server (miễn là hệ điều hành và phần cứng của bạn hỗ trợ nó). Đây là một giải pháp thay thế khả thi cho việc sử dụng độ bền chậm (yêu cầu SQL Server 2014) hoặc sử dụng tính năng đệm nhật ký liên tục (yêu cầu SQL Server 2016 SP1).
Kết luận
Tôi đã thảo luận về ba kỹ thuật để đạt được hiệu suất nhanh chóng giành chiến thắng với SQL Server:
- Điều chỉnh chỉ mục lưu trữ hàng thông thường có thể áp dụng cho tất cả các phiên bản của SQL Server và nó là một trong những công cụ tốt nhất trong kho vũ khí của bạn.
- Độ bền trì hoãn khả dụng trong SQL Server 2014 và mới hơn và nó có thể rất có lợi với một số loại khối lượng công việc (và các yêu cầu RPO). Bộ đệm nhật ký liên tục có sẵn trong SQL Server 2016 SP1 và nó mang lại lợi ích tương tự như độ bền chậm mà không có nguy cơ mất dữ liệu.
- Di chuyển một số loại tệp cơ sở dữ liệu nhất định sang bộ nhớ Intel Optane có thể giúp giảm bớt các vấn đề về hiệu suất với tempdb hoặc với tệp nhật ký giao dịch cơ sở dữ liệu của người dùng. Bạn có thể sử dụng bộ nhớ Optane với các phiên bản cũ của SQL Server và không yêu cầu thay đổi về mã hoặc cấu hình.