2009-08-22 7 views
2

私はタイムスタンプといくつかのデータを持つデータサンプルのテーブルを持っています。各テーブルには、タイムスタンプ上にクラスタ化されたインデックスがあり、次にデータ固有のキーがあります。データサンプルは必ずしも等距離にあるとは限りません。SQL ServerのGROUP BYで不必要な並べ替えを避ける?

グラフを描画するために、特定の時間範囲のデータをダウンサンプリングする必要があります。たとえば、100,000行からN(Nは約50)です。アルゴリズムの「正確さ」を妥協する必要がありますDSPの観点からは、パフォーマンス上の理由からSQLでこれを保持したいと思います。

私の現在のアイデアは、時間範囲のサンプルをN個のボックスにグループ化し、各グループの平均を取ることです。 SQLでこれを達成する1つの方法は、0からN-1(範囲を含む)の範囲の日付にパーティション関数を適用し、次にGROUP BYおよびAVGを適用することです。

このGROUP BYは、日付がクラスタードインデックスのものであり、パーティション関数が単調であるため、並べ替えなしで実行できると思います。ただし、SQL Serverはこれに気づいていないようで、実行コストの78%を表すソートを発行します(下の例を参照)。私が正しいと仮定し、この種の並べ替えは不要です、私はクエリを5倍速くすることができます。

SQL Serverで並べ替えをスキップする方法はありますか。あるいは、問題に近づくための良い方法がありますか?

乾杯。 ベン

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) 

答えて

2

dateクラスタ化されたキーをround(cast.. as float))のような式に使用して順序を保証できることは、SQL Serverが実際に知る方法はありません。それだけでトラックから捨てるだろう。 (... [email protected]) * @scaleを追加すると、完璧な混乱を招くことになります。このような式をソートしてグループ化する必要がある場合は、それらを永続的な計算列に格納し、それらの列でインデックスを作成します。浮動小数点型のような不正確な型を経由すると、永続化された計算列に対して式を使用できなくなる可能性があるので、おそらくDATEPARTを使用することをお勧めします。

datefloatが同等であることのトピックの更新

declare @f float, @d datetime; 
select @d = cast(1 as datetime); 
select @f = cast(1 as float); 
select cast(@d as varbinary(8)), cast(@f as varbinary(8)), @d, cast(@d as float) 

は、この生成されます

0x0000000100000000 0x3FF0000000000000 1900-01-02 00:00:00.000 1 

だから、彼らはaltough両方8に保存されていることがわかりますバイト(少なくともfloat(25...53))、0123の内部表現はfloatではありません。整数部分は曜日で、小数部分は時間です(しばしば仮定されています)。別の例与えるため

declare @d datetime; 
select @d = '1900-01-02 12:00 PM'; 
select cast(@d as varbinary(8)), cast(@d as float) 

0x0000000100C5C100 1.5 

を再びfloat@dを鋳造した結果は1.5が、0x0000000100C5C100の日時内部表現は、IEEE倍精度値2.1284E-314、ない1.5あろう。

+0

この例では、少なくとも分析するのは非常に簡単にする必要があります(... - 分)* @スケール部分。残念ながら、 "日付"の列を浮動小数点として格納しても差はありません。 最終的には正しいですが、SQL Serverがこれを自動的に解決することを期待するのはちょっと楽観的です。私が本当に望んでいるのは、データがすでにソートされていると仮定するように指示する方法です。 :) FLOATは不正確ですが、DATETIMEは内部的に単なるFLOATだと思いましたか? –

+0

日付と浮動小数点の「内部」仮定に関する私の更新を見てください。 –

+0

ああ、それはとても面白い!ありがとう。 –

1

はい、SQL-Serverは常に時間分割要約のSELECTのこの種のいくつかの問題がありました。 Analysis Servicesにはさまざまな処理方法がありますが、Data Servies側の方が制限されています。

私はあなたが試してみることはできません(ここでは何も試してみることはできません)は、yorパーティション定義を含んでいる2次的な "パーティションテーブル"を作ってそれに参加することです。

0

2つの質問

このクエリにはどのくらいの時間がかかりますか?

あなたは日付をソートしていますか?また、計画でそれは日付をソートですか?それは分割後?それは私の推測だろう。私はそれが最初のようなものだとは思っていません...それは、それが分割やグループ化の仕方をやり直す必要があるかもしれません。すでにリストを並べ替え、それはソート、それはそれはalredyソートされているので、それは非常に長い時間がかかるだろうとは思いませんでしょうなかった場合でも、とにかく

、...

関連する問題