Ich habe Tabellen mit Datenproben, mit einem Zeitstempel und einigen Daten. Jede Tabelle hat einen gruppierten Index für den Zeitstempel und dann einen datenspezifischen Schlüssel. Datenproben sind nicht notwendigerweise äquidistant.Vermeidung unnötiger Sortierung in SQL Server GROUP BY?
Ich muss die Daten in einem bestimmten Zeitbereich downsampling, um Graphen zu zeichnen - sagen wir von 100.000 Zeilen zu N, wo N ist etwa 50. Während ich muss möglicherweise Kompromisse bei der "Richtigkeit" des Algorithmus Aus DSP-Sicht möchte ich dies aus Performancegründen in SQL behalten.
Meine aktuelle Idee ist es, Proben im Zeitbereich in N-Boxen zu gruppieren, und dann den Durchschnitt jeder Gruppe zu nehmen. Eine Möglichkeit, dies in SQL zu erreichen, besteht darin, eine Partitionsfunktion auf das Datum anzuwenden, das von 0 bis N-1 (einschließlich) und dann GROUP BY und AVG reicht.
Ich denke, dass diese GROUP BY ohne eine Sortierung durchgeführt werden kann, da das Datum aus einem gruppierten Index stammt und die Partitionsfunktion monoton ist. SQL Server scheint dies jedoch nicht zu bemerken und gibt eine Sortierung aus, die 78% der Ausführungskosten ausmacht (im folgenden Beispiel). Angenommen, ich habe Recht, und diese Art ist unnötig, könnte ich die Abfrage 5 mal schneller machen.
Gibt es eine Möglichkeit, SQL Server zu zwingen, die Sortierung zu überspringen? Oder gibt es einen besseren Weg, das Problem anzugehen?
Prost. Ben
IF EXISTS(SELECT name FROM sysobjects WHERE name = N'test') DROP TABLE test
CREATE TABLE test
(
date DATETIME NOT NULL,
v FLOAT NOT NULL,
CONSTRAINT PK_test PRIMARY KEY CLUSTERED (date ASC, v ASC)
)
INSERT INTO test (date, v) VALUES ('2009-08-22 14:06:00.000', 1)
INSERT INTO test (date, v) VALUES ('2009-08-22 17:09:00.000', 8)
INSERT INTO test (date, v) VALUES ('2009-08-24 00:00:00.000', 2)
INSERT INTO test (date, v) VALUES ('2009-08-24 03:00:00.000', 9)
INSERT INTO test (date, v) VALUES ('2009-08-24 14:06:00.000', 7)
-- the lower bound is set to the table min for demo purposes; in reality
-- it could be any date
declare @min float
set @min = cast((select min(date) from test) as float)
-- similarly for max
declare @max float
set @max = cast((select max(date) from test) as float)
-- the number of results to return (assuming enough data is available)
declare @count int
set @count = 3
-- precompute scale factor
declare @scale float
set @scale = (@count - 1)/(@max - @min)
select @scale
-- this scales the dates from 0 to n-1
select (cast(date as float) - @min) * @scale, v from test
-- this rounds the scaled dates to the nearest partition,
-- groups by the partition, and then averages values in each partition
select round((cast(date as float) - @min) * @scale, 0), avg(v) from test
group by round((cast(date as float) - @min) * @scale, 0)
In diesem Beispiel sollte es recht einfach sein, zumindest zu analysieren die (... - @ min) * @skalen Teil. Das Speichern der Spalte "Datum" als Float scheint jedoch keinen Unterschied zu machen. Letztendlich haben Sie jedoch recht: Es ist ein wenig optimistisch zu erwarten, dass SQL Server dies automatisch löst. Was ich wirklich hoffe, ist eine Möglichkeit, zu sagen, dass die Daten bereits sortiert sind. :) In Bezug auf FLOAT ungenau, dachte ich, dass DATETIME nur ein FLOAT intern ist? –
Siehe meine Aktualisierung am Datum und float 'interne' Annahme. –
Ah, das ist sehr interessant! Vielen Dank. –