Nhóm theo giờ trên tập dữ liệu lớn


12

Sử dụng MS SQL 2008 Tôi đang chọn một trường trung bình từ 2,5 triệu bản ghi. Mỗi bản ghi đại diện cho một giây. MyField là trung bình hàng giờ của các hồ sơ 1 giây đó. Tất nhiên CPU máy chủ đạt 100% và quá trình lựa chọn mất quá nhiều thời gian. Tôi cần có thể lưu các giá trị trung bình đó để SQL không phải chọn tất cả các bản ghi đó cho mỗi yêu cầu. Những gì có thể được thực hiện?

  SELECT DISTINCT
         CONVERT(VARCHAR, [timestamp], 1)+' '+ CAST(DATEPART(Hh,[timestamp]) as VARCHAR) AS TimeStampHour,
         MIN([timestamp]) as TimeStamp,
         AVG(MyField) As AvgField
    FROM MyData
   WHERE TimeStamp > '4/10/2011'
GROUP BY CONVERT(VARCHAR, [timestamp], 1)+' '+ CAST(DATEPART(Hh,[timestamp]) as VARCHAR)
ORDER BY TimeStamp

6
TimeStamp có phải là một phần của một chỉ mục được nhóm không? Nó phải là ...

@antisanity - tại sao? anh ấy đang tối đa hóa CPU chứ không phải đĩa io
Jack nói hãy thử topanswers.xyz

Câu trả lời:


5

Một phần của truy vấn tối đa hóa CPU trong thời gian dài là các hàm trong mệnh đề GROUP BY và thực tế là việc nhóm luôn luôn yêu cầu một loại sắp xếp không được lập trong trường hợp này. Mặc dù một chỉ mục trên trường dấu thời gian sẽ giúp bộ lọc ban đầu, thao tác này phải được thực hiện trên mỗi hàng mà bộ lọc khớp. Tăng tốc điều này đang sử dụng một lộ trình hiệu quả hơn để thực hiện công việc tương tự như đề xuất của Alex sẽ giúp ích, nhưng bạn vẫn có một sự kém hiệu quả ở đó bởi vì sự kết hợp chức năng mà bạn sử dụng trình lập kế hoạch truy vấn sẽ không thể thực hiện được một cái gì đó sẽ được trợ giúp bởi bất kỳ chỉ mục nào, vì vậy nó sẽ phải chạy qua mọi hàng đầu tiên chạy các hàm để tính toán các giá trị nhóm, chỉ sau đó nó mới có thể ra lệnh cho dữ liệu và tính toán tổng hợp qua các nhóm kết quả.

Vì vậy, giải pháp là bằng cách nào đó tạo nhóm quy trình bằng một cái gì đó nó có thể sử dụng một chỉ mục cho, hoặc loại bỏ nhu cầu xem xét tất cả các hàng khớp cùng một lúc.

Bạn có thể duy trì một cột bổ sung cho mỗi hàng có chứa thời gian được làm tròn đến giờ và lập chỉ mục cột này để sử dụng trong các truy vấn đó. Điều này làm không chuẩn hóa dữ liệu của bạn nên có thể cảm thấy "bẩn" nhưng nó sẽ hoạt động và sẽ sạch hơn bộ đệm tất cả các tổng hợp để sử dụng trong tương lai (và cập nhật bộ đệm đó khi dữ liệu cơ sở bị thay đổi). Cột bổ sung phải được duy trì bằng kích hoạt hoặc là cột được tính toán bền vững, thay vì duy trì bằng logic ở nơi khác, vì điều này sẽ đảm bảo tất cả các vị trí hiện tại và tương lai có thể chèn dữ liệu hoặc cập nhật các cột dấu thời gian hoặc các hàng hiện có dẫn đến dữ liệu nhất quán trong dữ liệu mới cột. Bạn vẫn có thể lấy MIN (dấu thời gian) ra. Những gì truy vấn sẽ dẫn đến theo cách này vẫn là đi xuống tất cả các hàng (điều này rõ ràng không thể tránh được) nhưng nó có thể thực hiện theo thứ tự chỉ mục, xuất ra một hàng cho mỗi nhóm khi nó đến giá trị tiếp theo trong chỉ mục thay vì phải nhớ toàn bộ tập hợp cho một hoạt động sắp xếp không được lập trình trước khi có thể thực hiện nhóm / tổng hợp. Nó cũng sẽ sử dụng ít bộ nhớ hơn, vì nó sẽ không cần nhớ bất kỳ hàng nào từ các giá trị nhóm trước để xử lý cái mà nó đang xem bây giờ hoặc phần còn lại của chúng.

Phương thức đó loại bỏ nhu cầu tìm kiếm ở đâu đó trong bộ nhớ cho toàn bộ tập kết quả và thực hiện sắp xếp không được lập trình cho hoạt động nhóm và loại bỏ tính toán của các giá trị nhóm ra khỏi truy vấn lớn (chuyển công việc đó ra từng INSERTs / UPDATE riêng lẻ tạo ra dữ liệu) và nên cho phép các truy vấn đó chạy ở mức chấp nhận được mà không cần duy trì một kho lưu trữ kết quả tổng hợp riêng biệt.

Một phương pháp khôngkhông chuẩn hóa dữ liệu của bạn, nhưng vẫn yêu cầu cấu trúc bổ sung, là sử dụng "bảng thời gian", trong trường hợp này, một hàng chứa một hàng mỗi giờ trong tất cả thời gian bạn có thể xem xét. Bảng này sẽ không tiêu tốn một lượng không gian đáng kể trong DB hoặc kích thước đáng kể - để bao gồm khoảng thời gian 100 năm một bảng chứa một hàng hai ngày (bắt đầu và kết thúc giờ, chẳng hạn như '2011-01-01 @ 00: 00: 00.0000 ',' 2011-01-01 @ 00: 00: 59.9997 ', "9997" là số mili giây nhỏ nhất mà trường DATETIME sẽ không làm tròn đến giây tiếp theo) là cả hai phần của Khóa chính được phân cụm sẽ chiếm ~ 14Mbyte dung lượng (8 + 8 byte mỗi hàng * 24 giờ / ngày * 365,25 ngày / năm * 100, cộng với một chút chi phí cho cấu trúc cây của chỉ mục được phân cụm nhưng chi phí đó sẽ không đáng kể) .

SELECT CONVERT(VARCHAR, [timestamp], 1)+' '+ CAST(DATEPART(Hh,[timestamp]) as VARCHAR) AS TimeStampHour
     , MIN([timestamp]) as TimeStamp
     , AVG(MyField) As AvgField
FROM TimeRangeByHours tt
INNER JOIN MyData md ON md.TimeStamp BETWEEN tt.StartTime AND tt.EndTime
WHERE tt.StartTime > '4/10/2011'
GROUP BY tt.StartTime
ORDER BY tt.StartTime

Điều này có nghĩa là trình lập kế hoạch truy vấn có thể sắp xếp cho chỉ mục trên MyData.TimeStamp được sử dụng. Công cụ lập kế hoạch truy vấn phải đủ sáng để tìm ra nó có thể đi xuống bảng thuần hóa theo chỉ số trên MyData.TimeStamp, một lần nữa xuất ra một hàng cho mỗi nhóm và loại bỏ từng bộ hoặc hàng khi nó chạm vào giá trị nhóm tiếp theo. Không lưu trữ tất cả các hàng trung gian ở đâu đó trong RAM sau đó thực hiện sắp xếp không liên kết trên chúng. Tất nhiên phương pháp này yêu cầu bạn tạo bảng thời gian và đảm bảo rằng nó kéo dài đủ xa cả lùi và tiến, nhưng bạn có thể sử dụng bảng thời gian cho các truy vấn đối với nhiều trường ngày trong các truy vấn khác nhau, trong đó tùy chọn "cột thêm" sẽ yêu cầu một cột được tính toán thêm cho mỗi trường ngày bạn cần lọc / nhóm theo cách này và kích thước nhỏ của bảng (trừ khi bạn cần nó để kéo dài 10,

Phương thức bảng thời gian có một sự khác biệt bổ sung (có thể khá thuận lợi) so với tình huống hiện tại của bạn và giải pháp cột được tính toán: nó có thể trả về các hàng cho các khoảng thời gian không có dữ liệu, chỉ bằng cách thay đổi INNER THAM GIA trong truy vấn ví dụ ở trên trở thành một người ngoài hành tinh.

Một số người đề nghị không có bảng thời gian vật lý mà thay vào đó luôn trả về từ chức năng trả về bảng. Điều này có nghĩa là nội dung của bảng thời gian không bao giờ được lưu trữ trên đĩa (hoặc cần phải đọc từ) và nếu chức năng được viết tốt, bạn không bao giờ phải lo lắng về việc bảng thời gian cần phải kéo dài thời gian, nhưng tôi nghi ngờ chi phí CPU để tạo bảng trong bộ nhớ cho một số hàng, mọi truy vấn đều đáng để tiết kiệm một chút rắc rối khi tạo (và duy trì, nếu thời gian của nó cần vượt quá giới hạn phiên bản ban đầu của bạn).

Một lưu ý phụ: bạn cũng không cần mệnh đề DISTINCT trên truy vấn ban đầu của mình. Việc phân nhóm sẽ đảm bảo rằng các truy vấn này chỉ trả về một hàng trong một khoảng thời gian được xem xét, vì vậy DISTINCT sẽ không làm gì khác ngoài việc quay CPU nhiều hơn một chút (trừ khi trình hoạch định truy vấn thông báo rằng sự khác biệt đó sẽ là không có trong trường hợp đó bỏ qua nó và không sử dụng thêm thời gian CPU).


3

Xem câu hỏi này ( sàn một ngày ) Ngoài ra, tại sao phải chuyển đổi mọi thứ thành chuỗi - bạn có thể làm điều đó sau (nếu bạn cần).

  SELECT DISTINCT
         dateadd(hour,datediff(hour,0,[timestamp]),0) AS TimeStampHour,
         MIN([timestamp]) as TimeStamp,
         AVG(MyField) As AvgField
    FROM MyData
   WHERE TimeStamp > '4/10/2011'
GROUP BY dateadd(hour,datediff(hour,0,[timestamp],0);
ORDER BY TimeStamp

1

Bạn có muốn làm cho truy vấn nhanh hơn hoặc bạn đang hỏi làm thế nào để tạo một ảnh chụp nhanh dữ liệu và lưu nó?

Nếu bạn muốn làm cho nó nhanh hơn, bạn chắc chắn cần một chỉ mục trên trường TimeStamp. Ngoài ra, tôi sẽ đề nghị sử dụng điều này để chuyển đổi thành giờ:

select convert(varchar(13), getdate(), 121)

Nếu bạn cần tạo một ảnh chụp nhanh và sử dụng lại sau này, hãy sử dụng insert intođể tạo một bảng mới với kết quả từ truy vấn của bạn. Bảng chỉ mục theo và sử dụng nó. Từ những gì tôi hiểu, bạn sẽ cần một chỉ mục trên TimeStampHour.

Ngoài ra, bạn có thể thiết lập một công việc tổng hợp dữ liệu hàng ngày trong bảng tổng hợp mới của bạn.


-1

Bằng cách chuyển đổi nhóm của bạn theo mệnh đề thành một chuỗi như thế, về cơ bản, bạn sẽ biến nó thành một điểm nhấn không bị ràng buộc đến từng hàng trong cơ sở dữ liệu. Đây là những gì đang giết chết hiệu suất của bạn. Bất kỳ máy chủ nửa chừng nào cũng có thể xử lý một tổng hợp đơn giản như vậy trên một triệu bản ghi chỉ tốt nếu các chỉ mục được sử dụng đúng cách. Tôi sẽ sửa đổi truy vấn của bạn và đặt một chỉ mục cụm trên dấu thời gian của bạn. Điều đó sẽ giải quyết vấn đề hiệu suất của bạn trong khi tính toán dữ liệu mỗi giờ chỉ là vấn đề.


1
-1 - không, bạn không "biến nó thành một cú đánh không bị ràng buộc vào từng hàng trong cơ sở dữ liệu" - mọi chỉ mục trên TimeStampvẫn sẽ được sử dụng để lọc các hàng
Jack nói hãy thử topanswers.xyz

-3

Tôi sẽ xem xét từ bỏ ý tưởng thực hiện loại tính toán này bằng mô hình cơ sở dữ liệu quan hệ. Đặc biệt nếu bạn có nhiều điểm dữ liệu mà bạn thu thập giá trị mỗi giây.

Nếu bạn có tiền, bạn có thể cân nhắc mua một nhà sử học dữ liệu quy trình chuyên dụng như:

  1. Đồng phục Honeywell PHD
  2. Osisoft PI
  3. Aspentech IP21
  4. Vân vân.

Các sản phẩm này có thể lưu trữ một lượng lớn dữ liệu chuỗi thời gian cực kỳ dày đặc (ở định dạng độc quyền) đồng thời cho phép xử lý nhanh các truy vấn trích xuất dữ liệu. Các truy vấn có thể chỉ định nhiều điểm dữ liệu (còn được gọi là thẻ), khoảng thời gian dài (tháng / năm) và có thể thực hiện nhiều phép tính dữ liệu tóm tắt (bao gồm cả mức trung bình).

.. và trên một lưu ý chung: Tôi luôn cố gắng tránh sử dụng DISTINCTtừ khóa khi viết SQL. Nó hầu như không bao giờ là một ý tưởng tốt. Trong trường hợp của bạn, bạn sẽ có thể bỏ DISTINCTvà nhận được kết quả tương tự bằng cách thêm MIN([timestamp])vào GROUP BYmệnh đề của bạn .


1
Điều này không thực sự chính xác. Một cơ sở dữ liệu quan hệ là hoàn toàn tốt cho 2,5 triệu hồ sơ. Và anh ấy thậm chí không tham gia vào rất nhiều bàn. Dấu hiệu đầu tiên cho thấy bạn cần phải chuẩn hóa dữ liệu của mình hoặc chuyển sang hệ thống không liên quan là khi bạn thực hiện các phép nối lớn, phức tạp trên nhiều bảng. Tập dữ liệu của người đăng thực sự nghe có vẻ như là một hệ thống cơ sở dữ liệu quan hệ hoàn toàn chấp nhận được.
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.