当数据类型为位时,T-SQL处理的速度是否比1快1?

时间:2015-04-20 07:45:21

标签: sql-server performance tsql

默认情况下,某些T-SQL开发人员使用0表示如果(例如)用户处于活动状态,而当用户处于被动状态时,它的值为1.以下代码(在我的示例中)显示当前活动用户:

SELECT * FROM USERS WHERE ISACTIVE = 0 

我的问题是,此查询处理速度是否比以下更快? =>

SELECT * FROM USERS WHERE ISACTIVE = 1 

3 个答案:

答案 0 :(得分:5)

在最简单的情况下,没有区别。与任何性能问题一样,关键是测试,因此我设置了下表,其中包含1,000,000个随机分布的行(每个行为500,000,分别为1和0)。

CREATE TABLE #T (ID INT IDENTITY PRIMARY KEY, Filler CHAR(1000), Active BIT NOT NULL);
INSERT #T (Active)
SELECT  Active
FROM    (   SELECT  TOP 500000 Active = 1
            FROM    sys.all_objects AS a
                    CROSS JOIN sys.all_objects AS b
            UNION ALL
            SELECT  TOP 500000 Active = 0
            FROM    sys.all_objects AS a
                    CROSS JOIN sys.all_objects AS b
        ) AS t
ORDER BY NEWID();

下一步是对聚集索引扫描对每个扫描进行多长时间的简单测试:

SET STATISTICS TIME ON;
SET STATISTICS IO ON;

SELECT COUNT(Filler) FROM #T WHERE Active = 1;
SELECT COUNT(Filler) FROM #T WHERE Active = 0;

两者的执行计划完全相同:

enter image description here

与IO一样:

  

扫描计数5,逻辑读取143089,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。

然后查看经过的时间,超过10次(不够,但图片相当清晰)经过的时间是(以毫秒为单位)

Active = 1  Active = 0
---------------------------
125         132
86          86
89          61
83          89
88          89
63          64
85          93
126         125
100         117
66          68
--------------------------
91.1        92.4    (Mean)

因此平均差异大约为1ms,这不足以被视为物质。所以在你的情况下没有,没有区别。

然后我可能会对列上的排序索引产生影响,因此添加了一个:

CREATE INDEX IX_T__Active ON #T (Active) INCLUDE (Filler);

结果再次显示没有(相关)差异:

Active = 1  Active = 0
--------------------------
57          55
42          48
56          57
58          55
44          42
46          41
41          42
42          52
43          43
52          59
--------------------------
48.1        49.4

总之,它不会产生重大差异,我很确定这是Donald Knuth was referring too的过早优化。

答案 1 :(得分:1)

您可以在tempdb上快速测试。

    create table #tmp
    (
    id int, flag bit default(0)
    );

        DECLARE @max AS INT, @rc AS INT;
        SET @max = 200000;
        SET @rc = 1;


        INSERT INTO #tmp VALUES(1, 0);
        WHILE @rc * 2 <= @max
        BEGIN
          INSERT INTO #tmp SELECT id + @rc, 0 as flag FROM #tmp;
          SET @rc = @rc * 2;
        END

        INSERT INTO #tmp
          SELECT id + @rc, 1 as flag FROM #tmp WHERE id + @rc <= @max;
GO

set statistics time on
Go
select * from #tmp where flag = 1
set statistics time off
Go
set statistics time on
Go

select * from #tmp where flag = 0
set statistics time off
Go

尝试创建索引,您将看到更多的差异,即如果索引具有不同的值,位列的工作方式。

  1. 当两个标志的计数相等/不同时,结果将相同 此列的索引。
  2. 两个标志的计数结果相同 当列具有索引
  3. 时等于或接近相等
  4. 当两个标志的数量不相等且标志列
  5. 上存在索引时,结果会有所不同

答案 2 :(得分:0)

我不认为这个设计因为性能而存在,因为您的两个查询都会生成相同的执行计划。更重要的方面是,如果您在此列上有索引。

为什么要标记值为1的非活动用户还有其他多种原因。

为什么我会这样做的一些原因:

1)0的默认值为intbool

在某些ORM中(例如,EF6),您不必为状态列指定任何值,并且它将设置为0.因此,默认情况下,用户将处于活动状态。

在大多数系统中,大多数用户都是active。如果用户是inactive,则需要涵盖特殊情况。不是全部。

2)未来价值考虑因素

此列可能在将来包含不同的值,表示用户已被暂停,删除等。

拥有

没有多大意义
0-inactive, 1-active, 2-suspended, etc.

而不是

0-active, 1-inactive, 2-suspended, etc.

这样就可以通过简单的表达式status > 0来查询有问题的用户。