SQL Server 2016 - Bitwise与多位列

时间:2017-02-04 23:27:47

标签: sql-server bitwise-operators

我正在使用SQL Server数据库,该数据库当前使用整数字段来使用按位运算符对作业进行分类。

我认为这将是性能瓶颈,因此开始研究将此列拆分为多个索引位列。然而,经过一些测试后,我发现了一些不寻常的结果。按位查询的性能优于位列。

这是我正在测试的两个问题......

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

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

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

查询分析器报告相对成本为28%至72%。

表格相对较小,只有25K行。

任何人都可以建议为什么会这样吗?

我保持按位列没有问题,但只是好奇为什么它的表现更好,当我读过的所有内容似乎都表明单独的列应该更好。

1 个答案:

答案 0 :(得分: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)=@HotJob
AND (JobType&@FeaturedJob)=0;

SELECT *
FROM dbo.JobNormalized
WHERE HotJob = 1
AND FeaturedJob = 0;