6

(これはSQL Server の Floor a date に関連しています。)

DATETIME を無効にする決定論的式は存在しますか? これを計算列の数式として使用すると、次のようになります。

DATEADD(dd, DATEDIFF(dd, 0, [datetime_column]), 0)

その列にインデックスを配置するとエラーが発生します。

キー列 'EffectiveDate' が非決定論的または不正確であるため、インデックスを作成できません。

ただし、DATEDIFF と DATEADD はどちらも、定義上は決定論的関数です。キャッチはどこですか?出来ますか?

4

6 に答える 6

3

私の推測では、これはある種のバグです。SQL 2005 では、このようなインデックス付きビューを問題なく作成できました (コードは以下にあります)。SQL 2000 で実行しようとしたときに、あなたと同じエラーが発生しました。

以下は SQL 2000 で動作するようですが、インデックスが無視され、ビューから選択するたびに変換する必要があるという警告が表示されます。

CONVERT(CHAR(8), datetime_column, 112)

SQL 2005 で動作:

CREATE TABLE dbo.Test_Determinism (
    datetime_column DATETIME    NOT NULL    DEFAULT GETDATE())
GO

CREATE VIEW dbo.Test_Determinism_View
WITH SCHEMABINDING
AS
    SELECT
        DATEADD(dd, DATEDIFF(dd, 0, [datetime_column]), 0) AS EffectiveDate
    FROM
        dbo.Test_Determinism
GO

CREATE UNIQUE CLUSTERED INDEX IDX_Test_Determinism_View ON dbo.Test_Determinism_View (EffectiveDate)
GO
于 2008-11-21T19:51:16.233 に答える
2

列 [datetime_column] のデフォルト値は「getDate()」に設定されていますか??

もしそうなら、 getdate() 関数は非決定論的であるため、これによりこのエラーが発生します...

ユーザー定義関数が決定的か非決定的かは、関数のコーディング方法によって異なります。次の場合、ユーザー定義関数は決定論的です。

  1. 関数はスキーマにバインドされています。
  2. ユーザー定義関数によって呼び出されるすべての組み込み関数またはユーザー定義関数は決定論的です。
  3. 関数の本体は、関数のスコープ外のデータベース オブジェクトを参照しません。たとえば、決定論的関数は、関数に対してローカルなテーブル変数以外のテーブルを参照できません。
  4. この関数は、拡張ストアド プロシージャを呼び出しません。

これらの基準を満たさないユーザー定義関数は、非決定的としてマークされます。組み込みの非決定論的関数は、ユーザー定義関数の本体では許可されていません。

于 2008-11-21T17:28:10.970 に答える
1

元の質問に答える私の最良の答えは次のとおりです。

これを試して:

/* create a deterministic schema bound function */
CREATE FUNCTION FloorDate(@dt datetime)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN 
    RETURN CONVERT(datetime,  FLOOR(CONVERT(float, @dt)))
END
GO

テストするには、次のことを試してください。関数を参照するときは、計算列に「PERSISTED」を使用し、[dbo.] を使用することに注意してください。

/*create a test table */
CREATE TABLE [dbo].[TableTestFloorDate](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [TestDate] [datetime] NOT NULL,
    [TestFloorDate]  AS ([dbo].[FloorDate]([TestDate])) PERSISTED,
 CONSTRAINT [PK_TableTestFloorDate] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) 
) 

これで、計算列にインデックスを追加できるはずです (ただし、後で注意点を参照してください)。

CREATE INDEX IX_TestFloorDate ON  [dbo].[TableTestFloorDate](TestFloorDate)

ランダムなデータを何度でも挿入できますが、インデックスの使用/実行計画をテストする場合は、より多く (1000 以上) 挿入することをお勧めします

INSERT INTO TableTestFloorDate (TestDate) VALUES( convert(datetime, RAND()*50000))

結果を得る

SELECT * FROM TableTestFloorDate WHERE TestFloorDate='2013-2-2'

ここに問題があります...計算列で作成されたインデックスは使用されません! 代わりに、永続化されたフィールド TestFloorDate でデータを選択する場合でも、SQLServer (または少なくとも私のバージョン) は TestDate のインデックスを優先します。

CREATE INDEX IX_TestFloorDate ON  [dbo].[TableTestFloorDate](TestDate)

計算された永続化された列のインデックスがパフォーマンスの観点からメリットがあることは(記憶から)確信しています-独自の特定の使用法を試してテストする必要があるだけだと思います

(お役に立てば幸いです!)

于 2013-07-24T11:00:01.793 に答える
1

これを試して:

CAST(FLOOR(CAST([datetime_column] as FLOAT)) AS DateTime)

CONVERT オプションよりもはるかに高速です。

于 2008-11-21T17:29:11.997 に答える
0

Cade Roux によって尋ねられ、回答されたその質問を見てください。おそらく解決策は、WITH SCHEMABINDING を使用して関数を作成し、それを計算列で使用することです。

編集

あなたの目標は、その列にインデックスを作成できるようにすることだと理解しています。

計算列でそれができない場合、おそらく唯一のオプションは、通常の列を作成し、元の列を更新するたびにその列のデータを変更することです。(トリガーで言う)

于 2008-11-21T17:29:15.337 に答える
0

やや単純なものをお勧めします:

 cast(cast([datetime_column] as int) as datetime)

しかし、同じ問題に遭遇すると思います。

問題が datetime へのキャストバックにある場合はcast([datetime_column] as int)、インデックスのためだけに別のフィールドとして使用することを検討することをお勧めします。

于 2008-11-21T18:03:50.587 に答える