Có cách nào tốt hơn để tạo chuỗi trung bình thời gian động trên một tần số động không?


7

Tôi đã có một loạt các bảng với nhiều dữ liệu có độ chính xác cao được thu thập từ các thiết bị khác nhau. Các khoảng thời gian mà chúng được thu thập khác nhau và thậm chí là đi lang thang trong chuỗi thời gian. Người dùng của tôi muốn có khả năng chọn phạm vi ngày và nhận mức trung bình / phút / tối đa trên các biến này với tần suất cụ thể. Đây là cú đâm thứ hai tôi đã thực hiện, và nó hoạt động, nhưng tôi tự hỏi liệu có cách nào tốt hơn / nhanh hơn để thực hiện điều này không?

declare @start datetime
declare @end datetime
set @start = '3/1/2012'
set @end = '3/3/2012'
declare @interval int
set @interval = 300

declare @tpart table(
dt datetime
);

with CTE_TimeTable
as
(
select @start as [date]
union all
select dateadd(ss,@interval, [date])
from CTE_TimeTable
where DateAdd(ss,@interval, [date]) <= @end
)
insert into @tpart
select [date] from CTE_TimeTable
OPTION (MAXRECURSION 0);


select t.dt, avg(c.x1), min(c.x1), max(c.x2), avg(c.x2), min(c.x2), max(c.x2)  from clean.data c ,
@tpart t 
where
ABS(DateDIFF(ss, t.dt , c.Date) ) <= @interval /2
and
Date >= @start 
and 
Date <= @end
group by t.dt

Hiện tại có hơn 32721 hàng trong khoảng thời gian 3 ngày này, truy vấn này mất khoảng 43 giây để chạy và cung cấp cho tôi 577 hàng tôi mong đợi nhưng tôi muốn có được điều này nhanh hơn. Các hit lớn đến từ vòng lặp lồng nhau để thực hiện tham gia bên trong.


Câu hỏi đầu tiên tuyệt vời và chào mừng bạn đến với DBA.SE. Những chỉ số nào (cả cụm và không bao gồm) bạn có trên clean.data? Ngoài ra, bạn có thể giải thích lý do tại sao bạn tham gia chéo nó @tpart?
Nick Chammas

chỉ mục cụm trên Clean.data.Date. Tôi đã thử thực hiện một liên kết bên trong và chéo và kế hoạch truy vấn không thay đổi. Bugger ở đây là câu lệnh abs (dateiff (ss, t.dt, c.date)).
chris.w.mclean

Mục đích của DATEDIFFtuyên bố đó là gì?
Nick Chammas

2
Điều gì về việc sử dụng một cột được tính cho giá trị của ABS(DateDIFF(ss, t.dt , c.Date) )? Bạn có thể lập chỉ mục nó. Theo hiểu biết của tôi (có thể là WAAAAY sai), không phải hoạt động trên c.Datecột trong WHEREcơ bản làm cho chỉ mục trở nên vô dụng?
swasheck

2
@swasheck - Khoảng thời gian phụ thuộc vào đầu vào của người dùng, do đó, một cột được tính toán là không thể. Ngoài ra, chỉ mục vẫn có thể được sử dụng bởi tìm kiếm phạm vi trong phần sau của WHEREmệnh đề.
Nick Chammas

Câu trả lời:


4

Sự kết hợp của bạn giữa các bảng được nhúng trong một hàm khiến trình tối ưu hóa thực sự khó thực hiện bất cứ điều gì thông minh với nó. Tôi đoán nó phải so sánh mọi hàng trong một bảng với mọi hàng khác trong bảng khác.

Viết lại tham gia của bạn với một kiểm tra phạm vi sẽ nhanh hơn rất nhiều. Tôi cũng đã thêm một khóa chính vào biến bảng của bạn để loại bỏ một hoạt động sắp xếp khỏi kế hoạch truy vấn và thay vào đó tôi đã biến biến bảng của bạn thành một bảng tạm thời. Sự khác biệt trong các thử nghiệm của tôi là kế hoạch truy vấn bắt đầu sử dụng Parallelism.

declare @start datetime;
declare @end datetime;
set @start = '20120301';
set @end = '20120303';
declare @interval int;
set @interval = 300;

create table #tpart
(
  dt datetime primary key
);

with CTE_TimeTable
as
(
  select @start as [date]
  union all
  select dateadd(second ,@interval, [date])
  from CTE_TimeTable
  where dateadd(second, @interval, [date]) <= @end
)
insert into #tpart
select [date]
from CTE_TimeTable
option (maxrecursion 0);

select t.dt, avg(c.x1), min(c.x1), max(c.x2), avg(c.x2), min(c.x2), max(c.x2)
from clean.data c
  inner join #tpart t 
    on c.Date >= t.dt and
       c.Date < dateadd(second, @interval, t.dt)
group by t.dt;

drop table #tpart;

Lưu ý: Truy vấn này không trả về chính xác các khoảng thời gian giống như truy vấn của bạn. Nó sẽ chia phạm vi ngày thành các phần có kích thước bằng nhau trong đó truy vấn của bạn có một nửa khoảng thời gian bắt đầu và một nửa khoảng thời gian ở cuối phạm vi. Tất nhiên có thể sửa đổi truy vấn để tương đương với truy vấn của bạn nếu điều đó là mong muốn.

Cập nhật

Tôi đã thử nghiệm trên một bảng có tổng số 1036801hàng và 34560trong khoảng 2012-03-01đến 2012-03-03. Trong các thử nghiệm của tôi, truy vấn ban đầu mất 4,1 giây. Truy vấn trên mất 0,1 giây.

Tập lệnh để tạo dữ liệu thử nghiệm:

create table clean.data
(
    Date datetime primary key,
    x1 int,
    x2 int
);

go

with C as
(
  select cast('20120201' as datetime) as D
  union all
  select dateadd(second, 5, D)
  from C
  where D < '20120401'
)
insert into clean.data(Date, x1, x2)
select D, checksum(newid()) % 1000, checksum(newid()) % 1000
from C
option (maxrecursion 0);

0

Câu trả lời của Mikael Eriksson đã truyền cảm hứng cho tôi để sửa đổi mã gốc của mình một chút. Đây là những gì tôi đã đưa ra.

declare @tpart table(
dtStart datetime,
dtEnd datetime,
midTime datetime
);

with CTE_TimeTable
as
(
select Dateadd(ss,-(@interval/2), @start) as [sdate], Dateadd(ss,(@interval/2),@start) 
as [edate] , @start as [middate]
union all
select dateadd(ss,@interval, [sdate]) , dateadd(ss,@interval,[edate]) ,    
dateadd(ss,@interval, [middate])
from CTE_TimeTable
where DateAdd(ss,@interval, [middate]) < @end
)
insert into @tpart
select [sdate] , [edate] , [middate] from CTE_TimeTable
OPTION (MAXRECURSION 0);

Vì vậy, bây giờ biến bảng @tpart đã tính toán trước cả thời gian bắt đầu và kết thúc của truy vấn cũng như điểm giữa để nhóm. Vì vậy, bây giờ truy vấn của tôi trông như thế này:

select t.midtime, avg(c.x1), min(c.x1), max(c.x2), avg(c.x2), min(c.x2), max(c.x2)  from     
clean.data c inner join
@tpart t 
on c.Date >= t.dtStart and c.Date < t.dtEnd
group by t.midtime

Điều này cho tôi thời gian truy vấn khoảng 9 giây. Không hoàn toàn tốt như Mikael nhưng tốt hơn nhiều so với những gì tôi đã bắt đầu và đủ tốt cho người dùng của tôi. Con số này là hơn 80.000 hàng trong một ngày, tính trung bình thành các khối năm phút.

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.