2017-02-04 45 views
0

我正在使用SQL Server數據庫,該數據庫當前使用整數字段對使用按位運算符的作業進行分類。SQL Server 2016 - 按位與多位列

我認爲這將是一個性能瓶頸,因此開始調查將此列拆分爲多個索引位列。但是在做了一些測試之後,我發現了一些不尋常的結果。按位查詢性能優於位列。

這是我的兩個查詢我測試...

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

你看過這些查詢計劃嗎?我覺得第二個人最終可能會做一次關鍵的查找,但是如果不付出一些努力,我絕不會再重複。 –

+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;