私はいつもおもちゃのテーブルやデータベースを作成して自分のアイデアを披露するのが好きです. 以下はそのようなスニペットの 1 つです。
あなたのソリューションと私のソリューションについてのコメントを次に示します。
1 - 先頭にワイルド カードを使用して列をパターンと比較すると、クエリ オプティマイザーはインデックスを使用できません。したがって、これは全表スキャンになります。
2 - 私は常に null のテストが好きです。合体は、null 文字列をデフォルトで空の文字列にする優れた方法です。
3 - where ロジックに永続化された計算列を使用する場合、レコードが挿入または更新されるとデータベースに格納されます。
4 - 永続化された計算列はインデックスを持つことができるため、大きなテーブルでのテーブル スキャンが不要になります。
小さなテーブルの場合、テーブル スキャンの方が高速であるため、クエリ インデックス ヒントを使用する必要がありました。
また、member_fk や begin_date を追加することもできます。IE - より多くの作業/実際の例のテスト。
5 - 最後になりましたが、ウィンドウの分割と row_number() 関数を使用して最新の行を見つけます。
WHERE 句のステートメントの SELECT 部分で計算を参照できないため、これを CTE にバンドルしました。
ここにはいくつかの良い概念があります:
- ワイルド カード パターン検索は、全テーブル スキャンに等しい
- null の常にテスト/アカウント
- 速度のためのインデックスとして永続化された計算列
- 上位の結果を選択するためのグループ化関数の使用
ご不明な点がございましたら、お気軽にお問い合わせください。
心から
ジョン
-- Drop old table
if object_id('tempdb.dbo.contracts') > 0
drop table tempdb.dbo.contracts;
go
-- Create new table
create table tempdb.dbo.contracts
(
id_num int identity(1,1),
member_fk int,
main_flag bit,
begin_date smalldatetime,
end_date smalldatetime,
description_txt varchar(512),
do_not_use_flag as
(
-- must have these words
(
case
when lower(coalesce(description_txt, '')) like '%gold%' then 0
when lower(coalesce(description_txt, '')) like '%silver%' then 0
when lower(coalesce(description_txt, '')) like '%bronze%' then 0
when lower(coalesce(description_txt, '')) like '%executive%' then 0
else 1
end
)
+
-- must not have these words
(
case
when lower(coalesce(description_txt, '')) like '%mitarbeiter%' then 1
when lower(coalesce(description_txt, '')) like '%kind%' then 1
when lower(coalesce(description_txt, '')) like '%teen%' then 1
when lower(coalesce(description_txt, '')) like '%kid%' then 1
else 0
end
)
+
-- must have begin_date <= end_date
(
case
when begin_date is null then 1
when end_date is null then 0
when begin_date <= end_date then 0
else 1
end
)
+
(
-- toss out non-main records
case
when main_flag = 1 then 0
else 1
end
)
) persisted
);
go
-- add index on id include flag
create nonclustered index ix_contracts
on tempdb.dbo.contracts (do_not_use_flag);
go
-- add data to table
insert into tempdb.dbo.contracts (member_fk, main_flag, begin_date, end_date, description_txt)
values
-- shows up
(1, 1, getdate() - 5, getdate(), 'Silver - good contract for DBA'),
-- main contract <> 1
(1, 0, getdate() - 5, getdate(), 'Gold - good contract for DBA'),
-- no flag = true
(1, 1, getdate() - 5, getdate(), 'Bronze - good contract for Teen'),
-- end < begin
(1, 1, getdate(), getdate()-5, 'Bronze - good contract for DBA'),
(2, 1, getdate() - 5, getdate(), 'Executive - good contract for DBA');
go
-- wait 5 seconds
WAITFOR DELAY '00:00:02';
go
insert into tempdb.dbo.contracts (member_fk, main_flag, begin_date, end_date, description_txt)
values
(2, 1, getdate() - 4, getdate(), 'Executive - good contract for DBA');
go
-- show the raw data
select * from tempdb.dbo.contracts as c
go
-- show the data
;
with cte_contract_by_recent_begin_dte
as
(
select
ROW_NUMBER() OVER (PARTITION BY member_fk ORDER BY begin_date desc) as top_id,
*
from
tempdb.dbo.contracts as c with(index(ix_contracts))
where
c.do_not_use_flag = 0
)
select * from cte_contract_by_recent_begin_dte as cte where cte.top_id = 1