時間ベースの条件で結合やフィルタリングを行う場合は、パラメータを文字列として渡すのではなく、リテラルを使用することをお勧めします。これにより、ソース・システムはこれらのパラメータを変換する必要がなくなります。
例
Date |
|
Time |
|
Timestamp |
|
詳しくはLiteralsをご覧ください。
この例では、単純な日付比較がパフォーマンスに悪影響を与えるシナリオを見ていきます:
SELECT
"SalesOrderID"
,
"OrderDate"
FROM
"mssql_advworks_2019.AdventureWorks2019.Sales.SalesOrderHeader"
WHERE
OrderDate >=
'2011-05-31'
or
OrderDate >= {d
'2011-05-31'
} LIMIT 500;;
クエリプランを調べると、元のクエリがどのように変換され、データソースにプッシュダウンされたかがわかります:
OrderDate >= '2011-05-31'
は と訳されました;(convert(g_0.OrderDate, string) >= '2011-05-31')
OrderDate >= {d '2011-05-31' }
は に翻訳されました。(g_0.OrderDate >= {ts'2011-05-31 00:00:00.0'})
MSSQL Server Profilerを使用することで、さらに多くの洞察を得ることができます。これはMSSQLが受信した実際のクエリです:
SELECT
TOP
500 g_0.
"SalesOrderID"
AS
"c_0"
, g_0.
"OrderDate"
AS
"c_1"
FROM
"AdventureWorks2019"
.
"Sales"
.
"SalesOrderHeader"
g_0
WHERE
(
convert
(
varchar
(34), g_0.
"OrderDate"
, 21) >= N
'2011-05-31'
COLLATE
Latin1_General_CS_AS)
OR
g_0.
"OrderDate"
>=
CAST
(
'2011-05-31 00:00:00.0'
AS
DATETIME2)'
WHERE
句のこの部分は非常に効率的です、g_0."OrderDate" >= CAST('2011-05-31 00:00:00.0' AS DATETIME2)'
。文字列は一度日付時刻の値に変換され、その後カラムと比較されます。もし "OrderDate "カラムにインデックスがあれば、この比較はインデックスを利用することができます。
(convert(varchar(34), g_0."OrderDate", 21) >= N'2011-05-31' COLLATE Latin1_General_CS_AS)
は非効率で遅い。テーブルのすべての行は、バイナリ保存形式から人間が読める文字列に変換され、日付文字列と比較されなければなりません。日付から文字列への変換は、OrderDate
のインデックスが無視されることも意味します。この変換はパフォーマンスを著しく低下させるので、避けるべきです。