我正在使用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行。
任何人都可以建议为什么会这样吗?
我保持按位列没有问题,但只是好奇为什么它的表现更好,当我读过的所有内容似乎都表明单独的列应该更好。
答案 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;