CPU 100% với kế hoạch thực hiện xấu


8

Tôi có một vấn đề lớn với các đột biến CPU 100% vì một kế hoạch thực thi tồi được sử dụng bởi một truy vấn cụ thể. Tôi dành hàng tuần để giải quyết bằng chính tôi.

Cơ sở dữ liệu của tôi

DB mẫu của tôi chứa 3 bảng được đơn giản hóa.

[Bộ dữ liệu]

CREATE TABLE [model].[DataLogger](
    [ID] [bigint] IDENTITY(1,1) NOT NULL,
    [ProjectID] [bigint] NULL,
CONSTRAINT [PK_DataLogger] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

[Biến tần]

CREATE TABLE [model].[Inverter](
    [ID] [bigint] IDENTITY(1,1) NOT NULL,
    [SerialNumber] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_Inverter] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY],
 CONSTRAINT [UK_Inverter] UNIQUE NONCLUSTERED 
(
    [DataLoggerID] ASC,
    [SerialNumber] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

ALTER TABLE [model].[Inverter] WITH CHECK
ADD CONSTRAINT [FK_Inverter_DataLogger]
FOREIGN KEY([DataLoggerID])
REFERENCES [model].[DataLogger] ([ID])

[Biến tần]

CREATE TABLE [data].[InverterData](
    [InverterID] [bigint] NOT NULL,
    [Timestamp] [datetime] NOT NULL,
    [DayYield] [decimal](18, 2) NULL,
 CONSTRAINT [PK_InverterData] PRIMARY KEY CLUSTERED 
(
    [InverterID] ASC,
    [Timestamp] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)

Số liệu thống kê và bảo trì

Các [InverterData]bảng chứa nhiều triệu hàng (khác ở chỗ nhiều trường PaaS) phân chia trong chiếc thuyền hàng tháng.

Tất cả các bộ chỉ mục được phân mảnh và tất cả các chỉ số xây dựng lại / tổ chức lại khi cần thiết trên một lượt hàng ngày / hàng tuần.

Sự truy vấn của tôi

Truy vấn là Entity Framework được tạo và cũng đơn giản. Nhưng tôi chạy 1.000 lần mỗi phút và hiệu suất là điều cần thiết.

SELECT
[Extent1].[InverterID] AS [InverterID],
[Extent1].[DayYield] AS [DayYield]
FROM [data].[InverterDayData] AS [Extent1]
INNER JOIN [model].[Inverter] AS [Extent2] ON [Extent1].[InverterID] = [Extent2].[ID]
INNER JOIN [model].[DataLogger] AS [Extent3] ON [Extent2].[DataLoggerID] = [Extent3].[ID]
WHERE ([Extent3].[ProjectID] = @p__linq__0)
AND ([Extent1].[Date] = @p__linq__1) OPTION (MAXDOP 1)

Các MAXDOP 1gợi ý là cho một vấn đề khác với một kế hoạch song song chậm.

Kế hoạch "tốt"

Trong 90% thời gian, kế hoạch được sử dụng nhanh như chớp và trông như thế này:

kế hoạch nhanh

Vấn đề

Trong ngày, kế hoạch tốt ngẫu nhiên thay đổi thành kế hoạch xấu và chậm.

Kế hoạch "xấu" được sử dụng trong 10-60 phút và sau đó đổi lại thành kế hoạch "tốt". Kế hoạch "xấu" tăng vọt CPU lên đến 100% vĩnh viễn.

Cái này nó thì trông như thế nào:

kế hoạch chậm

Những gì tôi cố gắng cho đến nay

Suy nghĩ đầu tiên của tôi Hash Matchlà cậu bé hư. Vì vậy, tôi đã sửa đổi truy vấn với một gợi ý mới.

...Extent1].[Date] = @p__linq__1) OPTION (MAXDOP 1, LOOP JOIN)

Các LOOP JOINlực lượng nên sử dụng Nested Loopngay lập tức Hash Match.

Kết quả là kế hoạch 90% trông giống như trước đây. Nhưng kế hoạch cũng thay đổi ngẫu nhiên thành xấu.

Kế hoạch "xấu" bây giờ trông như thế này (thứ tự vòng lặp bảng đã thay đổi):

kế hoạch cũng chậm

CPU cũng liếc tới 100% trong kế hoạch "xấu mới".

Giải pháp?

Tôi nghĩ rằng để buộc kế hoạch "tốt". Nhưng tôi không biết nếu đây là một ý tưởng tốt.

Bên trong kế hoạch là một chỉ số được đề xuất bao gồm tất cả các cột. Nhưng điều này sẽ tăng gấp đôi bảng hoàn chỉnh và làm chậm tốc độ cao thường xuyên.

Làm ơn giúp tôi!


Cập nhật 1 - liên quan đến bình luận @James

Dưới đây là cả hai gói (một số trường bổ sung được hiển thị trong kế hoạch vì nó từ bảng thực):

Kế hoạch tốt

Kế hoạch xấu 1 (Hash Match)

Kế hoạch xấu 2 (Vòng lặp lồng nhau)

Cập nhật 2 - liên quan đến câu trả lời @David Fowler

Kế hoạch xấu là đá vào giá trị tham số ngẫu nhiên. Vì vậy, bình thường tôi @p__linq__1 ='2016-11-26 00:00:00.0000000' @p__linq__0 =20825ngày lỗ và hơn là kế hoạch xấu đến cùng một giá trị.

Tôi biết vấn đề đánh hơi thông số từ các thủ tục được lưu trữ và cách tránh chúng trong SP. Bạn có gợi ý cho tôi cách tránh vấn đề này cho truy vấn của tôi không?

Tạo chỉ mục được đề xuất sẽ bao gồm tất cả các cột. Điều này sẽ tăng gấp đôi bảng hoàn chỉnh và làm chậm quá trình chèn, vốn thường xuyên cao. Điều đó không "cảm thấy" đúng khi xây dựng một chỉ mục chỉ đơn giản là sao chép bảng. Ngoài ra tôi có nghĩa là tăng gấp đôi kích thước dữ liệu của bảng lớn này.

Cập nhật 3 - liên quan đến bình luận @David Fowler

Nó cũng không hoạt động và tôi nghĩ nó không thể. Để hiểu rõ hơn tôi sẽ giải thích cho bạn cách truy vấn được gọi.

Giả sử tôi có 3 thực thể trong [DataLogger]bảng. Cả ngày tôi gọi 3 truy vấn giống nhau trong một vòng lặp đi lặp lại:

Truy vấn cơ sở: ...WHERE ([Extent3].[ProjectID] = @p__linq__0) AND ([Extent1].[Date] = @p__linq__1)

Tham số:

  1. @p__linq__0 = 1; @p__linq__1 = '2018-01-05 00:00:00.0000000'
  2. @p__linq__0 = 2; @p__linq__1 = '2018-01-05 00:00:00.0000000'
  3. @p__linq__0 = 3; @p__linq__1 = '2018-01-05 00:00:00.0000000'

Tham số @p__linq__1luôn luôn là cùng một ngày. Nhưng nó chọn kế hoạch xấu một cách ngẫu nhiên trên một truy vấn chạy lần lượt với một kế hoạch tốt trước đó. Với cùng một tham số!

Cập nhật 4 - liên quan đến bình luận @Nic

Việc bảo trì chạy mỗi đêm và trông như thế này.

Mục lục

Nếu một Index bị phân mảnh nhiều hơn 5% thì nó được tổ chức lại ...

ALTER INDEX [{index}] ON [{table}] REORGANIZE

Nếu một Index bị phân mảnh nhiều hơn 30% thì nó sẽ được xây dựng lại ...

ALTER INDEX [{index}] ON [{table}] REBUILD WITH (ONLINE=ON, MAXDOP=1)

Nếu Index được phân vùng, nó sẽ được chứng minh về sự phân mảnh và thay đổi trên mỗi phân vùng ...

ALTER INDEX [{index}] ON [{table}] REBUILD PARTITION = {partitionNr} WITH (ONLINE=ON, MAXDOP=1)

Số liệu thống kê

Tất cả các số liệu thống kê sẽ được cập nhật nếu modification_countercao hơn 0 ...

UPDATE STATISTICS [{schema}].[{object}] ([{stats}]) WITH FULLSCAN

hoặc trên phân vùng ..

UPDATE STATISTICS [{schema}].[{object}] ([{stats}]) WITH RESAMPLE ON PARTITIONS({partitionNr})

Việc bảo trì bao gồm tất cả các số liệu thống kê, cũng là số liệu tự động tạo.

Thí dụ


Bạn không đề cập đến điều này, nhưng bạn đã cập nhật số liệu thống kê trên bất kỳ bảng nào gần đây chưa?
Nic

Thx @Nic Tôi đã thêm một bản cập nhật cho câu hỏi. Xin vui lòng xem thông tin chi tiết ở đó.
Steffen Mangold

Câu trả lời:


3

Nhìn vào các kế hoạch, có một vài khác biệt giữa cái tốt và cái xấu. Điều đầu tiên cần lưu ý là kế hoạch tốt thực hiện tìm kiếm trên Biến tầnDayData khi cả hai kế hoạch xấu đều thực hiện quét. Tại sao lại như vậy, nếu bạn kiểm tra các hàng ước tính, bạn sẽ thấy rằng kế hoạch tốt đang mong đợi 1 hàng trong đó các kế hoạch xấu đang mong đợi 6661 và khoảng 7000 hàng.

Bây giờ hãy xem các giá trị tham số được biên dịch,

Kế hoạch tốt @ p__linq__1 = '2016-11-26 00: 00: 00.0000000' @ p__linq__0 = 20825

Các kế hoạch xấu @ p__linq__1 = '2018-01-03 00: 00: 00.0000000' @ p__linq__0 = 20686

Vì vậy, nó trông giống như một vấn đề đánh hơi tham số, bạn đang chuyển các giá trị tham số nào khi nó hoạt động kém?

Có một khuyến nghị về chỉ số trong các kế hoạch xấu trên Biến tần có vẻ hợp lý, tôi sẽ thử chạy nó và xem liệu nó có giúp gì cho bạn không. Nó có thể cho phép SQL thực hiện quét trên bảng.


cảm ơn câu trả lời của bạn Tôi đã sửa đổi câu hỏi cho bạn (ở cuối).
Steffen Mangold

Tôi đã không nhận ra chỉ số được đề xuất bao trùm toàn bộ bảng, đó không phải là một ý tưởng tốt. Bạn chỉ có thể thử một chỉ mục trên cột ngày.
David Fowler

sử dụng gợi ý TỐI ƯU HÓA sẽ buộc kế hoạch biên dịch với các giá trị tốt, TÙY CHỌN (TỐI ƯU HÓA CHO (@ p__linq__1 = '2016-11-26 00: 00: 00.0000000', @ p__linq__0 20825)) nhưng hãy cẩn thận với điều đó để đảm bảo rằng nó sẽ không gây ra cho bạn bất kỳ cơn đau đầu bất ngờ nào
David Fowler

hey @david Tôi đã đăng một bản cập nhật.
Steffen Mangold

Ok đó là một vấn đề đánh hơi thông số! Do số lượng hàng khác nhau bên trong bảng được phân chia, Index XEMK hoặc SCAN được chọn. Tôi đã sửa nó với ...OPTION (OPTIMIZE FOR UNKNOWN)gợi ý.
Steffen Mangold
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.