12

SQL Serverの日時フィールドを持つテーブルから(時刻を無視して)個別の日付を選択するための優れたクエリがあるかどうか疑問に思っています。

私の問題は、サーバーに実際にこれを実行させることではありません(この質問はすでに見たことがあり、DISTINCTを使用して同様の機能がすでに用意されています)。問題は、それをより迅速に行うためのトリックがあるかどうかです。使用しているデータを使用すると、現在のクエリは、(別のインデックス付き列でフィルタリングした後)約40,000行のデータがあり、日付列にインデックスがあり、クエリが常に取得できる、約80の異なる日を返します。 5秒以上。遅すぎる。

データベース構造を変更することはオプションかもしれませんが、あまり望ましくありません。

4

10 に答える 10

11

私は以下を使用しました:

CAST(FLOOR(CAST(@date as FLOAT)) as DateTime);

floatこれは、日付をaに変換し、の小数である「時間」部分を切り捨てることによって、日付から時間を削除しfloatます。

少し不格好に見えますが、私が1日を通して繰り返し使用する大きなデータセット(〜100,000行)でうまく機能します。

于 2009-08-20T16:34:40.877 に答える
8

これは私のために働く:

SELECT distinct(CONVERT(varchar(10), {your date column}, 111)) 
FROM {your table name}
于 2011-10-10T12:21:30.913 に答える
7

Every option that involves CAST or TRUNCATE or DATEPART manipulation on the datetime field has the same problem: the query has to scan the entire resultset (the 40k) in order to find the distinct dates. Performance may vary marginally between various implementaitons.

What you really need is to have an index that can produce the response in a blink. You can either have a persisted computed column with and index that (requires table structure changes) or an indexed view (requires Enterprise Edition for QO to consider the index out-of-the-box).

Persisted computed column:

alter table foo add date_only as convert(char(8), [datetimecolumn], 112) persisted;
create index idx_foo_date_only on foo(date_only);

Indexed view:

create view v_foo_with_date_only
with schemabinding as 
select id
    , convert(char(8), [datetimecolumn], 112) as date_only
from dbo.foo;   
create unique clustered index idx_v_foo on v_foo_with_date_only(date_only, id);

Update

To completely eliminate the scan one could use an GROUP BY tricked indexed view, like this:

create view v_foo_with_date_only
with schemabinding as 
select
    convert(char(8), [d], 112) as date_only
    , count_big(*) as [dummy]
from dbo.foo
group by convert(char(8), [d], 112)

create unique clustered index idx_v_foo on v_foo_with_date_only(date_only)

The query select distinct date_only from foo will use this indexed view instead. Is still a scan technically, but on an already 'distinct' index, so only the needed records are scanned. Its a hack, I reckon, I would not recommend it for live production code.

AFAIK SQL Server does not have the capability of scanning a true index with skipping repeats, ie. seek top, then seek greater than top, then succesively seek greater than last found.

于 2009-08-20T17:03:16.700 に答える
3

最も簡単な方法は、日付部分のみの計算列を追加し、それを選択することです。テーブルを変更したくない場合は、ビューでこれを行うことができます。

于 2009-08-20T16:35:06.710 に答える
3

既存のクエリが40,000行で5秒以上かかる理由はわかりません。

100,000行のテーブルに対して次のクエリを試したところ、0.1秒未満で返されました。

SELECT DISTINCT DATEADD(day, 0, DATEDIFF(day, 0, your_date_column))
FROM your_table

(このクエリはおそらく日付列のインデックスを利用できないことに注意してください。ただし、1秒間に数十回実行していないと仮定すると、かなり高速であるはずです。)

于 2009-08-20T17:15:26.613 に答える
2

アップデート:

2M以下のソリューションは、テーブルでの効率性についてテストされており、しかし40 ms.

DISTINCTインデックス付きの計算された列のプレーンはかかり9 secondsました。

パフォーマンスの詳細については、ブログの次のエントリを参照してください。


残念ながら、SQL Serverのオプティマイザは Oracle のSKIP SCANMySQLのも実行できませんINDEX FOR GROUP-BY

それはいつもStream Aggregate時間がかかります。

再帰を使用して可能な日付のリストを作成し、CTEそれをテーブルに結合できます。

WITH    rows AS (
        SELECT  CAST(CAST(CAST(MIN(date) AS FLOAT) AS INTEGER) AS DATETIME) AS mindate, MAX(date) AS maxdate
        FROM    mytable
        UNION ALL
        SELECT  mindate + 1, maxdate
        FROM    rows
        WHERE   mindate < maxdate
        )
SELECT  mindate
FROM    rows
WHERE   EXISTS
        (
        SELECT  NULL
        FROM    mytable
        WHERE   date >= mindate
                AND date < mindate + 1
        )
OPTION  (MAXRECURSION 0)

これはより効率的になりますStream Aggregate

于 2009-08-20T16:42:33.810 に答える
1

私はこれを使いました

SELECT
DISTINCT DATE_FORMAT(your_date_column,'%Y-%m-%d') AS date
FROM ...
于 2011-02-23T18:10:58.030 に答える
0

ステップの抽出や日付の再フォーマットを避けたい場合(おそらく(全表スキャンを強制することによって)遅延の主な原因です)、日付を日時の一部のみに保存する以外に方法はありませんが、残念ながらデータベース構造を変更する必要があります。

SQL Server 2005以降を使用している場合は、永続化された計算フィールドが最適です。

特に指定がない限り、計算列は仮想列です。
テーブルに物理的に保存されていません。それらの値は毎回再計算されます
それらがクエリで参照される時間。データベースエンジンはPERSISTEDを使用します
物理的に格納するCREATETABLEおよびALTERTABLEステートメントのキーワード
テーブル内の計算列。それらの値は、列があるときに更新されます
それは彼らの計算変更の一部です。計算列をとしてマークすることによって
PERSISTED、決定論的である計算列にインデックスを作成できます
しかし、正確ではありません。
于 2009-08-20T16:44:19.267 に答える
0

他のフィルタリングされた列の述語は何ですか?他のフィルタリングされた列のインデックスに続いて日時フィールドから改善が得られるかどうかを試しましたか?

私はここで大部分を推測していますが、おそらく100000行のセットを40000にフィルタリングしてから、並べ替え(おそらく何が起こっているのか)を実行する5秒は、私には不合理な時間のようには思えません。なぜ遅すぎると言うのですか?期待と合わないから?

于 2009-08-20T16:46:11.167 に答える
0

日付を変換するだけです:dateadd(dd,0, datediff(dd,0,[Some_Column]))

于 2009-08-20T17:20:24.340 に答える