SQL Server二進位彙總運算效能的研究

來源:互聯網
上載者:User

程式開發中涉及許可權管理,系統採用了整形數記錄使用者權限,權限等級設定為:

Level1 1
Level2 2
Level3 4
Level4 8
Level5 16
Level6 31
Level7 32
Level8 64
Level9 127
Level10 128
Level11 255
Level12 65535

 

 

在資料庫中如果一個使用者a權限等級為1, 他的三個角色分別被授予許可權2,2,4

則使用者的許可權應該返回7,即1|2|2|4.

由於T-SQL中沒有二進位的彙總函式,我們的預存程序中起先使用遊標迴圈記錄逐條進行OR運算,然後輸出結果。在進行壓力測試時發現,當系統壓力達到一定程度時SQL Server伺服器CPU會達到100%,而且一直居高不下。

 

大家知道,臭名昭著的遊標一直是SQL編程人員聲討的對象,於是我改用迴圈讀取表記錄逐條進行OR運算,然後輸出結果。

在同樣的壓力下進行測試,結果仍然不理想。

 

根據網上文章http://www.eggheadcafe.com/software/aspnet/33139293/bitwise-aggregate-functio.aspx,有如下兩種方法可以對int進行二進位彙總運算。

 

If you have a numbers table:

SELECT      SUM(mytable.mycolumn),
SUM(DISTINCT Bits.bitval)
FROM        mytable
INNER JOIN (SELECT POWER(2, n-1) AS bitval
FROM   dbo.Numbers
WHERE  n <= 31) AS Bits
ON    mytable.value & Bits.bitval = Bits.bitval;

 

Or if you don't have one (why not?) and don't want to create one (why
not??????), use this instead:

SELECT SUM(mycolumn),
MAX(mycolum & 1)
+ MAX(mycolum & 2)
+ MAX(mycolum & 4)
+ MAX(mycolum & 8)
+ MAX(mycolum & 16)
(....)
+ MAX(mycolum & 1073741824)
FROM   mytable;

 

 

於是又分別按照這兩種方法寫了一遍許可權查詢。

測試指令碼和結果如下:

DECLARE @Access table
(Id INT identity primary key,
 Access INT)

DECLARE @insertCount INT
SET @insertCount=10000

WHILE @insertCount>0
BEGIN

 INSERT INTO @Access(Access)
 SELECT 0 Access
 UNION ALL
 SELECT 1 Access
 UNION ALL
 SELECT 2 Access
 UNION ALL
 SELECT 4 Access
 UNION ALL
 SELECT 8 Access
 UNION ALL
 SELECT 16 Access
 UNION ALL
 SELECT 31 Access
 UNION ALL
 SELECT 32 Access
 UNION ALL
 SELECT 64 Access
 UNION ALL
 SELECT 127 Access
 UNION ALL
 SELECT 128 Access
 UNION ALL
 SELECT 65535 Access
 SET @insertCount = @insertCount - 1
END

DECLARE @SumAccess int
SET @SumAccess=0

--方法1,使用遊標
SELECT getdate()
DECLARE @CurrentAccess INT

DECLARE access_cursor CURSOR FOR
SELECT Access
FROM @Access

OPEN access_cursor
FETCH NEXT FROM access_cursor INTO @CurrentAccess

WHILE @@FETCH_STATUS = 0
BEGIN

SET @SumAccess=@SumAccess|@CurrentAccess
FETCH NEXT FROM access_cursor INTO @CurrentAccess

END

CLOSE access_cursor
DEALLOCATE access_cursor

SELECT @SumAccess AS UsingCursor
SELECT getdate()

--方法2,使用迴圈

DECLARE @MinId INT
DECLARE @MaxId INT

SET @SumAccess=0
SELECT @MinId=Min(Id)
FROM @Access

SELECT @MaxId=Max(Id)
FROM @Access

WHILE @MinId<=@MaxId
BEGIN
 SELECT @SumAccess=@SumAccess|Access
 FROM @Access
 WHERE Id=@MinId
 
 SET @MinId=@MinId+1
END

SELECT @SumAccess AS UsingWhileLoop
SELECT GETDATE()
--方法3,使用二進位彙總方法1
SELECT
  (SUM(DISTINCT(Access & 0x000001))
 + SUM(DISTINCT(Access & 0x000002))
 + SUM(DISTINCT(Access & 0x000004))
 + SUM(DISTINCT(Access & 0x000008))
 + SUM(DISTINCT(Access & 0x000010))
 + SUM(DISTINCT(Access & 0x000020))
 + SUM(DISTINCT(Access & 0x000040))
 + SUM(DISTINCT(Access & 0x000080))
 + SUM(DISTINCT(Access & 0x000100))
 + SUM(DISTINCT(Access & 0x000200))
 + SUM(DISTINCT(Access & 0x000400))
 + SUM(DISTINCT(Access & 0x000800))
 + SUM(DISTINCT(Access & 0x001000))
 + SUM(DISTINCT(Access & 0x002000))
 + SUM(DISTINCT(Access & 0x004000))
 + SUM(DISTINCT(Access & 0x008000))

 --可根據許可權的最大值繼續增加,我們的系統中0x008000為最大值
  ) as BitWiseAggre1
FROM @Access;

SELECT GETDATE();

--方法3,使用二進位彙總方法2
WITH AccessValue (Access)
AS
(
 SELECT 1 --必須寫成1否則如果寫成0x000001 SQL Server會將資料類型預設為varbinary,這樣,下面的處理中將無法進行二進位OR運算
 UNION ALL
 SELECT 0x000002
 UNION
 SELECT 0x000004
 UNION ALL
 SELECT 0x000008
 UNION ALL
 SELECT 0x000010
 UNION ALL
 SELECT 0x000020
 UNION ALL
 SELECT 0x000040
 UNION ALL
 SELECT 0x000080
 UNION ALL
 SELECT 0x000100
 UNION ALL
 SELECT 0x000200
 UNION ALL
 SELECT 0x000400
 UNION ALL
 SELECT 0x000800
 UNION ALL
 SELECT 0x001000
 UNION ALL
 SELECT 0x002000
 UNION ALL
 SELECT 0x004000
 UNION ALL
 SELECT 0x008000
 --可根據許可權的最大值繼續增加,我們的系統中0x008000為最大值
)

SELECT   
SUM(DISTINCT a.Access) AS BitWiseAggre2
FROM        Access_test t
INNER JOIN AccessValue a
ON    t.Access & a.Access = a.Access

SELECT GETDATE()

 

100,000 records  
Using Cursor 3.28s
Using While Loop 1.34s
Bit wise Aggregate Sum1 2s
Bit wise Aggregate Sum2 0.4s
   
   
10,000 records  
Using Cursor 0.33s
Using While Loop 0.25s
Bit wise Aggregate Sum1 0.2s
Bit wise Aggregate Sum2 0.033s
   
   
1,000 records  
Using Cursor 0.15s
Using While Loop 0.12s
Bit wise Aggregate Sum1 0.02s
Bit wise Aggregate Sum2 0s

 

 

結論:使用二進位彙總方法中第二種方法,即定義包含許可權資料的常量表,效能最佳。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.