2017-02-04 35 views
0

現在、整数型フィールドを使用してビット単位の演算子を使用してジョブを分類するSQL Serverデータベースを使用しています。SQL Server 2016 - ビット単位と複数のビット列

これはパフォーマンスのボトルネックになると想定していたので、この列を複数のインデックス付きビット列に分割して調べ始めました。しかし、いくつかのテストをした後、私はいくつかの珍しい結果に気付きました。ビット単位のクエリはビット列より優れています。

これら

は私の2つのクエリ私がテストしています...

declare @HotJob int = 32; 
declare @FeaturedJob int = 64; 

select * from Job 
where (JobType&@HotJob)[email protected] 
and (JobType&@FeaturedJob)=0; 

select * from Job 
where HotJob = 1 
and FeaturedJob = 0; 

クエリアナライザは、相対的なコストは28%〜72%であることを報告しています。

テーブルは比較的小さく、わずか25K行です。

これがなぜこのようになるのか誰にも示唆できますか?

私はビット単位の列を維持することに問題はありませんが、私が読んだことが分かれば、別々の列がうまくいくはずです。

+0

これらのクエリプランを見てきましたか?私は第2のものがキールックアップを終えるかもしれないように感じます、しかし私は決して何の努力もなしにそれを再現することができませんでした。 –

+0

ビット単位クエリの場合、キールックアップとインデックススキャンを実行しています。ビット単位でない問合せでは、クラスタ化された索引スキャンのみを実行します。 – user1751825

+0

私は、さまざまな数の列を返すところで、いくつかの他の組み合わせを試しました。違いは必ずしも重要ではありませんが、ビット単位のバージョンは常にコストがかかりません。 – user1751825

答えて

0

複数の列にアクセスするオーバーヘッドは、単一の列のオーバーヘッドよりも大きいようです。ただし、正規化された列を使用すると、フルスキャンを避けるために役立つ可能性のあるインデックスを作成できます。相対的なコスト(私が塩の穀物で取る)は、以下のカバー指数の例で91%と9%です。最適なインデックス作成はクエリとデータによって異なるため、実験が必要な場合があります。

CREATE TABLE dbo.JobBitMask(
     JobID int NOT NULL 
     CONSTRAINT PK_JobBitMask PRIMARY KEY 
    , JobType int NOT NULL 
    , JobData varchar(100) NOT NULL 
    ); 

WITH 
    t4 AS (SELECT n FROM (VALUES(0),(0),(0),(0)) t(n)) 
    ,t256 AS (SELECT 0 AS n FROM t4 AS a CROSS JOIN t4 AS b CROSS JOIN t4 AS c CROSS JOIN t4 AS d) 
    ,t16M AS (SELECT ROW_NUMBER() OVER (ORDER BY (a.n)) AS num FROM t256 AS a CROSS JOIN t256 AS b CROSS JOIN t256 AS c) 
INSERT INTO dbo.JobBitMask WITH (TABLOCKX) (JobID, JobType, JobData) 
SELECT num, CASE num%10 WHEN 0 THEN 32 ELSE 0 END + CASE num%3 WHEN 0 THEN 64 ELSE 0 END, 'other data' 
FROM t16M 
WHERE num <= 25000; 

CREATE TABLE dbo.JobNormalized(
     JobID int NOT NULL 
     CONSTRAINT PK_JobNormalized PRIMARY KEY 
    , HotJob bit NOT NULL 
    , FeaturedJob bit NOT NULL 
    , JobData varchar(100) NOT NULL 
    ); 
CREATE INDEX idx1 ON dbo.JobNormalized(HotJob, FeaturedJob) INCLUDE(JobData); 

WITH 
     t4 AS (SELECT n FROM (VALUES(0),(0),(0),(0)) t(n)) 
    , t256 AS (SELECT 0 AS n FROM t4 AS a CROSS JOIN t4 AS b CROSS JOIN t4 AS c CROSS JOIN t4 AS d) 
    , t16M AS (SELECT ROW_NUMBER() OVER (ORDER BY (a.n)) AS num FROM t256 AS a CROSS JOIN t256 AS b CROSS JOIN t256 AS c) 
INSERT INTO dbo.JobNormalized WITH (TABLOCKX) (JobID, HotJob, FeaturedJob, JobData) 
SELECT num, CASE num%10 WHEN 0 THEN 1 ELSE 0 END, CASE num%3 WHEN 0 THEN 1 ELSE 0 END, 'other data' 
FROM t16M 
WHERE num <= 25000; 

CREATE INDEX idx ON dbo.JobNormalized(HotJob, FeaturedJob) INCLUDE(JobData); 

DECLARE @HotJob int = 32; 
DECLARE @FeaturedJob int = 64; 

SELECT * 
FROM dbo.JobBitMask 
WHERE (JobType&@HotJob)[email protected] 
AND (JobType&@FeaturedJob)=0; 

SELECT * 
FROM dbo.JobNormalized 
WHERE HotJob = 1 
AND FeaturedJob = 0; 
関連する問題