2019年1月31日 星期四

SQL Server multi computed columns reference the same column

env:Windows Server 2016
       SQL Server 2012 SP1

看到這個標題一定覺得這有什麼好講的,直接加計算行欄位不就可以了嗎?
我當時也是覺得如此,但是還真的不可以~~

情境:有一張表TESTTB01有一create的欄位,資料形態是datetimeoffset,時區有+08:00,也有+07:00。需要用日期來判斷資料是哪一天。但是在不同時區造成日期的差異。
因此想利用計算型欄位來找出資料是屬於哪一天,並優化查詢效能。

資料約5億筆

1.直接在資料表參考同一欄位,建立3個計算行欄位。
command:
ALTER TABLE [dbo].[TESTTB01] ADD CreateDate AS (CONVERT(date, Created)) PERSISTED;
GO
ALTER TABLE [dbo].[TESTTB01] ADD CreateUTC AS (Created AT TIME ZONE 'UTC') PERSISTED;
GO
ALTER TABLE [dbo].[TESTTB01] ADD CreateUTCDate AS (CONVERT(date, (Created AT TIME ZONE 'UTC'))) PERSISTED;
GO

值行超過4小時,錯誤
Msg 4936, Level 16, State 1, Line 4
Computed column 'CreateUTC' in table 'TESTTB01' cannot be persisted because the column is non-deterministic.
Msg 4936, Level 16, State 1, Line 6
Computed column 'CreateUTCDate' in table 'TESTTB01' cannot be persisted because the column is non-deterministic.

2.嘗試重新建立空測試表:TESTTB01_NEW
command:
CREATE TABLE [dbo].[TESTTB01_NEW](
[Id] [uniqueidentifier] NOT NULL,
[Status] [int] NOT NULL,
[Created] [datetimeoffset](7) NOT NULL,
 CONSTRAINT [PK_TESTTB01_NEW] PRIMARY KEY NONCLUSTERED 
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

3.建立function並設定計算型欄位
command:
CREATE FUNCTION dbo.FnCreateUTC(@DATE datetimeoffset)  
RETURNS datetimeoffset
AS  
BEGIN  
     DECLARE @CreateUTC DATETIMEOFFSET;  
     SELECT  @CreateUTC= (Created AT TIME ZONE 'UTC') FROM dbo.TESTTB01_NEW

     RETURN(@CreateUTC);  
END;  
GO

ALTER TABLE [dbo].[TESTTB01_NEW] ADD CreateUTC AS dbo.FnCreateUTC(created) PERSISTED;
GO

錯誤訊息,不可以使用PERSISTED
Msg 4936, Level 16, State 1, Line 49
Computed column 'CreateUTC' in table 'TESTTB01_NEW' cannot be persisted because the column is non-deterministic

4.不使用PERSISTED
command:
ALTER TABLE [dbo].[TESTTB01_NEW] ADD CreateUTC AS dbo.FnCreateUTC(created) ;
GO

5.再補上兩個計算型欄位,一個使用function,一個不使用function
command:
ALTER TABLE [dbo].[TESTTB01_NEW] ADD CreateUTC AS dbo.FnCreateUTC(created);
GO
ALTER TABLE [dbo].[TESTTB01_NEW] ADD CreateUTCDate AS (CONVERT(date, (Created AT TIME ZONE 'UTC')));
GO







結論:每一個欄位只能被一個計算型欄位參考,但是不侷限被function使用

在步驟3是一個不好的寫法,這支function效能很差,function內容改成以下效能好很多
     DECLARE @CreateUTCDate DATETIMEOFFSET;  
     SET @CreateUTCDate= (CONVERT(date, (@DATE AT TIME ZONE 'UTC')))




2019年1月27日 星期日

SQL Server 2012 check identity jump number after restarting service

env:Windows Server 2016
       SQL Server 2012 SP1

最近一位朋友問我一個問題,SQL Server服務重啟後identity跳號問題。
我記得以前SQL Server 2008R2有遇到,記得是利用script找到重啟服務前的號碼重設,可是這個方式在多表的時候是一個很大的負擔。
Trace flag 272也是一個解決方式。

1.建立測試DB
command:
CREATE DATABASE [TBTEST02]
 CONTAINMENT = NONE
 ON  PRIMARY 
( NAME = N'TBTEST02', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL11.SQL2012\MSSQL\DATA\TBTEST02.mdf' , SIZE = 4096KB , FILEGROWTH = 1024KB )
 LOG ON 
( NAME = N'TBTEST02_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL11.SQL2012\MSSQL\DATA\TBTEST02_log.ldf' , SIZE = 1024KB , FILEGROWTH = 10%)
GO


2.建立測試資料表與資料
command:
CREATE TABLE dbo.TEST01 (id int identity, name varchar(20))
insert into dbo.TEST01(name) values('john'),('mary')
select * from dbo.TEST01











3.檢查identity資訊
command:
dbcc checkident('TEST01', NORESEED)

identity現在的值是2









4.重啟SQL Server服務,並增加新的測試資料
command:
insert into dbo.TEST01(name) values('sean'),('larry')
select * from dbo.TEST01

重啟後發生跳號狀況














5.測試Trace flag 272,加到啟動參數,併重啟SQL Server服務



















6.檢查啟動後identity值
command:
dbcc checkident('TEST01', NORESEED)

identitt值1003









7.增加測試數據
command:
insert into dbo.TEST01(name) values('sean'),('larry')
select * from dbo.TEST01

配置identity值1004, 1005















若多表有identity有跳號問題,Trace flag也許是不錯的選擇,一定要放在啟動參數裡面才有效果。或是利用script重新設定



2019年1月26日 星期六

SQL Server should create clustered index before non-clustered index in exists table

env:Windows Server 2016
       SQL Server 2016 SP2

有一張表格要補上clustered index與non-clustered index。這是一張既有表格且有4億筆資料,裡面也有一支non-clustered index。
統計資訊的更新程度是80000000筆。

1.執行create non-clustered index後再執行clustered index
command:
CREATE NONCLUSTERED INDEX [IX_TESTId_CreatOn]
ON [dbo].[TESTTB] ([TESTId],[CreatOn])
INCLUDE ([Id],[LISTId],[Amount],[Revenue],[Session])
WITH(ONLINE=ON, DATA_COMPRESSION=ON)
GO

CREATE CLUSTERED INDEX [IX_CreatOn] ON [dbo].[TESTTB]
(
[CreatOn] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = ON, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION=PAGE) ON [PRIMARY]
GO

在建立clustered index花費許多時間,主要是掃描既有索引造成。利用SSMS建立cluster index會提示其他所引也會重建。
執行次序
servername
db_date
table_name
idx_id
index_name
row_count
data_used_mb
Exec(Mins)
1
TESTDB01
TESTDB01
dbo.TESTTB
7
IX_TESTId_CreatOn
404502153
17368
51
2
TESTDB01
TESTDB01
dbo.TESTTB
1
IX_CreatOn
404502153
47358
94


2.這次讓clustered index優先建立
command:
CREATE CLUSTERED INDEX [IX_CreatOn] ON [dbo].[TESTTB]
(
[CreatOn] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = ON, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION=PAGE) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [IX_TESTId_CreatOn]
ON [dbo].[TESTTB] ([TESTId],[CreatOn])
INCLUDE ([Id],[LISTId],[Amount],[Revenue],[Session])
WITH(ONLINE=ON, DATA_COMPRESSION=ON)
GO

這次可以發現建立clustered index時間大幅縮短。
執行次序
servername
db_date
table_name
idx_id
index_name
row_count
data_used_mb
Exec(Mins)
1
TESTDB01
TESTDB01
dbo.TESTTB
1
IX_CreatOn
404502153
47358
50
2
TESTDB01
TESTDB01
dbo.TESTTB
7
IX_TESTId_CreatOn
404502153
17368
43


結論:
若要在既有表格建立索引,clustered index要優先處理。
若表格內已經有許多non-clustered index,是否要建立空表後再進行資料複製移轉?這是值得考慮的問題。


2019年1月20日 星期日

CentOS Docker install sql server 2017 with volume

env: CentOS 7
        Docker docker-ce-18.05.0.ce
        SQL Server 2017 for Linux

Docker可以視為一種虛擬器,而使用的image很像以前使用過的Live光碟,只要放入光碟機啟動後,就是一個可以立即使用的作業系統。缺點是重新掛載就是回復到原本預設狀態。
這次要使用到volume的參數把docker image啟動後的狀態保存下來。

1.執行docker指令掛載SQL Server 2017 image
增加參數"-v",指定存放路徑"/dockervol"
command:
docker run -e 'ACCEPT_EULA=Y' -e 'MSSQL_SA_PASSWORD=Passw0rd@1234' -p 1433:1433 -v /dockervol:/var/opt/mssql -d microsoft/mssql-server-linux:2017-latest


[root@localhost ~]# docker run -e 'ACCEPT_EULA=Y' -e 'MSSQL_SA_PASSWORD=Passw0rd@1234' -p 1433:1433 -v /dockervol:/var/opt/mssql -d microsoft/mssql-server-linux:2017-latest
cf7ccddde4fd629f2d1e4e4c58ca071127d5bfd5f3b5f31ed0c2ca467b25489f
[root@localhost ~]# docker container ps -a
CONTAINER ID        IMAGE                                      COMMAND                  CREATED             STATUS                           PORTS                    NAMES
cf7ccddde4fd        microsoft/mssql-server-linux:2017-latest   "/opt/mssql/bin/sqls…"   5 minutes ago       Up 5 minutes                     0.0.0.0:1433->1433/tcp   infallible_rosalind


2.檢查存放路徑下的內容
可以發現到SQL Server的系統資料庫已經存放到"/dockervol/data"

[root@localhost /]# ls
bin   dev        etc   lib    media  opt   root  sbin  sys  usr
boot  dockervol  home  lib64  mnt    proc  run   srv   tmp  var
[root@localhost /]# cd dockervol/
[root@localhost dockervol]# ls
data  log  secrets
[root@localhost dockervol]# cd data
[root@localhost data]# ls
master.mdf   modellog.ldf  msdbdata.mdf  tempdb.mdf
mastlog.ldf  model.mdf     msdblog.ldf   templog.ldf
[root@localhost data]# pwd
/dockervol/data
[root@localhost data]#


3.我們利用sqlcmd在本機做連線查詢驗證

[root@localhost ~]# sqlcmd -S 0.0.0.0,1433 -U sa -P 'Passw0rd@1234'
1> select @@servername
2> go
                                                                                                                               
--------------------------------------------------------------------------------------------------------------------------------
cf7ccddde4fd                                                                                                                   

(1 rows affected)


[root@localhost ~]# sqlcmd -S 100.168.1.202,1433 -U sa -P 'Passw0rd@1234'
1> exit
[root@localhost ~]#



4.再利用SSMS從遠端主機做連線查詢
















6.嘗試用sqlcmd建立測試DB: dbvolume
可以看到新的data file存放在路徑"/dockervol/data"


[root@localhost ~]# sqlcmd -S 0.0.0.0,1433 -U sa -P 'Passw0rd@1234'
1> create database dbvolume
2> go
1>

[root@localhost data]# ls -ltr
total 54976
-rw-r-----. 1 root root  8388608 Jul  6 11:20 tempdb.mdf
-rw-r-----. 1 root root  4653056 Jul  6 11:31 master.mdf
-rw-r-----. 1 root root  8388608 Jul  6 11:38 model.mdf
-rw-r-----. 1 root root  8388608 Jul  6 11:38 modellog.ldf
-rw-r-----. 1 root root   524288 Jul  6 11:56 msdblog.ldf
-rw-r-----. 1 root root 15466496 Jul  6 11:56 msdbdata.mdf
-rw-r-----. 1 root root  8388608 Jul  6 12:06 templog.ldf
-rw-r-----. 1 root root  2097152 Jul  6 12:09 mastlog.ldf
[root@localhost data]# ls -ltr
total 71360
-rw-r-----. 1 root root  8388608 Jul  6 11:20 tempdb.mdf
-rw-r-----. 1 root root  4653056 Jul  6 11:31 master.mdf
-rw-r-----. 1 root root   524288 Jul  6 11:56 msdblog.ldf
-rw-r-----. 1 root root 15466496 Jul  6 11:56 msdbdata.mdf
-rw-r-----. 1 root root  8388608 Jul  6 12:06 templog.ldf
-rw-r-----. 1 root root  8388608 Jul  6 12:14 model.mdf
-rw-r-----. 1 root root  8388608 Jul  6 12:14 modellog.ldf
-rw-r-----. 1 root root  8388608 Jul  6 12:14 dbvolume.mdf
-rw-r-----. 1 root root  2097152 Jul  6 12:14 mastlog.ldf
-rw-r-----. 1 root root  8388608 Jul  6 12:14 dbvolume_log.ldf
[root@localhost data]#



2019年1月17日 星期四

SQL Server enable trace flag 1118 with alter database

env: Windows Server 2016
        SQL Server 2016 SP2

上次介紹利用Alter database啟用trace flag 1117 "SQL Server enable trace flag 1117 with alter database",這次要介紹使用"Alter database"啟用trace flag 1118


Trace flag:1118
移除伺服器上大部分的單一頁面配置,以減少 SGAM 頁面的競爭情況。 建立新物件時,根據預設,前八頁會從不同的範圍 (混合範圍) 進行配置。 之後若需要更多頁面時,將會從相同的範圍 (統一範圍) 加以配置。 SGAM 頁面可用以追蹤這些混合範圍,因此若出現多個混合頁面配置,它會很快地成為瓶頸。 這個追蹤旗標會在建立新物件時,從相同的範圍配置所有八個頁面,進而將掃描 SGAM 頁面的需求降到最低。 如需詳細資訊,請參閱此 Microsoft 支援服務文章 (機器翻譯)。

注意: 從 SQL Server 2016 (13.x) 開始,此行為由 ALTER DATABASE 的 SET MIXED_PAGE_ALLOCATION 選項控制,追蹤旗標 1118 沒有任何作用。 如需詳細資訊,請參閱 ALTER DATABASE SET 選項 (Transact-SQL)。

範圍: 只限全域

1.建立測試DB
command:
CREATE DATABASE [TBTEST02]
 CONTAINMENT = NONE
 ON  PRIMARY 
( NAME = N'TBTEST01', FILENAME = N'E:\SQLData\TBTEST02.mdf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
 LOG ON 
( NAME = N'TBTEST01_log', FILENAME = N'E:\SQLLog\TBTEST02_log.ldf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
GO


2.檢查測試DB否預設啟用trace flag 1117 
command:
SELECT
[NAME],
is_mixed_page_allocation_on
FROM SYS.databases 
WHERE [name] ='TBTEST02'

查詢後可以發現"is_mixed_page_allocation_on"為0


3.再次檢查測試DB與tempdb
command:
SELECT
[NAME],
is_mixed_page_allocation_on
FROM SYS.databases 
WHERE [name] IN ('TBTEST02','tempdb')

查詢後可以發現"is_mixed_page_allocation_on"為0

4.建立測試表並建立測試資料
command:
USE [TBTEST02]
GO
CREATE TABLE test01

  Name CHAR(8000)
) ON [PRIMARY]
GO

USE [TBTEST02]
GO
INSERT INTO [TBTEST02].dbo.test01 VALUES ('Larry222222222222')
GO 20


5.檢查測試DB的extent分布
command:
USE [TBTEST02]
GO
SELECT
DB_NAME(database_id) as DBName, 
OBJECT_NAME(object_id) as ObjectName,
extent_page_id, page_type_desc
FROM sys.dm_db_database_page_allocations(DB_ID('TBTEST02'),
OBJECT_ID('test01'),NULL,NULL,'DETAILED')
--WHERE OBJECT_NAME(object_id) = 'test02'
go

extent_page_id : 320
所有的8kb pages放置在相同的extent

extent_page_id : 328
extent已經填滿,下一個extent已經配置

extent_page_id : 336
extent沒有填滿,下一個extent尚未配置



























6.建立新的測試DB
command:
CREATE DATABASE [TBTEST03]
 CONTAINMENT = NONE
 ON  PRIMARY 
( NAME = N'TBTEST03', FILENAME = N'E:\SQLData\TBTEST03.mdf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
 LOG ON 
( NAME = N'TBTEST03_log', FILENAME = N'E:\SQLLog\TBTEST03_log.ldf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
GO


7.建立測試表
command:
USE [TBTEST02]
GO
CREATE TABLE test01

  Name CHAR(8000)
) ON [PRIMARY]
GO

8.利用"Alter databaase"啟用trace flag 1117功能
command:
ALTER DATABASE [TBTEST03] SET MIXED_PAGE_ALLOCATION ON

9.增加測試資料
command:
USE [TBTEST03]
GO
INSERT INTO [TBTEST03].dbo.test01 VALUES ('Larry222222222222')
GO 20

10.檢查測試DB的extent分布
command:
USE [TBTEST03]
GO
SELECT
DB_NAME(database_id) as DBName, 
OBJECT_NAME(object_id) as ObjectName,
extent_page_id, 
page_type_desc,
is_mixed_page_allocation
FROM sys.dm_db_database_page_allocations(DB_ID('TBTEST03'),
OBJECT_ID('test01'),NULL,NULL,'DETAILED')
--WHERE OBJECT_NAME(object_id) = 'test02'
go

 extent_page_id : 336
所有的8kb pages放置在相同的extent

extent_page_id : 344
extent已經填滿,下一個extent已經配置

extent_page_id : 352
extent沒有填滿,下一個extent尚未配置































11.在TempDB啟用trace flag 1118
command:
USE [master]
GO
ALTER DATABASE [Tempdb] SET MIXED_PAGE_ALLOCATION ON
GO


這是比較可惜的地方!!!!




2019年1月13日 星期日

SQL Server enable trace flag 1117 with alter database

env: Windows Server 2016
        SQL Server 2016 SP2

上次在"SQL Server speedup create index in alwayson"透過trace flag 610策是建立索引的速度,
同時也發現trace flag 1117, 1118, 610在SQL Server 2016可以透過Alter database啟用,甚至trace flag 610已經啟用。

這次要驗證使用"Alter database"啟用trace flag 1117。

1.trace flag 1117官方說明。

DBCC TRACEON - Trace Flags (Transact-SQL)
Trace flag:1117
When a file in the filegroup meets the autogrow threshold, all files in the filegroup grow.

Note: Starting with SQL Server 2016 (13.x) this behavior is controlled by the AUTOGROW_SINGLE_FILE and AUTOGROW_ALL_FILES option of ALTER DATABASE, and trace flag 1117 has no effect. For more information, see ALTER DATABASE File and Filegroup Options (Transact-SQL).

Scope: global only


2.建立測試db"TBTEST01"
command:
CREATE DATABASE [TBTEST01]
 CONTAINMENT = NONE
 ON  PRIMARY 
( NAME = N'TBTEST01', FILENAME = N'E:\SQLData\TBTEST01.mdf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
 LOG ON 
( NAME = N'TBTEST01_log', FILENAME = N'E:\SQLLog\TBTEST01_log.ldf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
GO

3.增加新的Filegroup與Datafiles。
command:
USE [master]
GO
ALTER DATABASE [TBTEST01] ADD FILEGROUP [DATA]
GO
ALTER DATABASE [TBTEST01] ADD FILE ( NAME = N'TBTEST01_DATA01', FILENAME = N'E:\SQLData\TBTEST01_DATA01.ndf' , SIZE = 8192KB , FILEGROWTH = 65536KB ) TO FILEGROUP [DATA]
GO
ALTER DATABASE [TBTEST01] ADD FILE ( NAME = N'TBTEST01_DATA02', FILENAME = N'E:\SQLData\TBTEST01_DATA02.ndf' , SIZE = 8192KB , FILEGROWTH = 65536KB ) TO FILEGROUP [DATA]
GO










4.檢查測試資料庫Filegroup是否啟用auto growth
command:
USE [TBTEST01]
GO
SELECT
    DB_NAME() DBName,
    DBF.name AS FileName,
    FileGrp.name as DBFileGrpName,
    FileGrp.is_autogrow_all_files AutoGrowthEnable
FROM sys.database_files AS DBF
JOIN sys.filegroups AS FileGrp
    ON DBF.data_space_id = FileGrp.data_space_id









5.測試資料庫Filegroup啟用auto growth
command:
USE [master]
GO
ALTER DATABASE [TBTEST01] MODIFY FILEGROUP [DATA] AUTOGROW_ALL_FILES;
GO

6.再次檢查測試資料庫Filegroup是否啟用auto growth
command:
USE [TBTEST01]
GO
SELECT
    DB_NAME() DBName,
    DBF.name AS FileName,
    FileGrp.name as DBFileGrpName,
    FileGrp.is_autogrow_all_files AutoGrowthEnable
FROM sys.database_files AS DBF
JOIN sys.filegroups AS FileGrp
    ON DBF.data_space_id = FileGrp.data_space_id







7.在測試的DB與Filegroup "DATA"建立測試表並增加測資料
command:
USE [TBTEST01]
GO
CREATE TABLE test01
( id INT IDENTITY(1,1),
  Name VARCHAR(20)
) ON [DATA]
GO
USE [TBTEST01]
GO
INSERT INTO [TBTEST01].dbo.test01 VALUES ('Larry222222222222')
GO 3000000

結果:







8.依據結果只能說Filegroup大小相同,利用script來證明。
command:
USE [TBTEST01]
DECLARE @curr_tracefilename VARCHAR(500) ; 
DECLARE @base_tracefilename VARCHAR(500) ; 
DECLARE @indx INT ;

SELECT @curr_tracefilename = PATH FROM sys.traces WHERE is_default = 1 ; 
SET @curr_tracefilename = reverse(@curr_tracefilename);
SELECT @indx  = patindex('%\%', @curr_tracefilename) ;
SET @curr_tracefilename = reverse(@curr_tracefilename) ;
SET @base_tracefilename = left( @curr_tracefilename,len(@curr_tracefilename) - @indx) + '\log.trc' ;  

SELECT
DatabaseName
,[Filename]
,(Duration/1000) AS [Duration(Secs)]
,StartTime
,EndTime
,(IntegerData*8.0/1024) AS ChangeInSize 
FROM ::fn_trace_gettable( @base_tracefilename, DEFAULT ) 
WHERE EventClass >=  92 AND EventClass <=  95 AND ServerName = @@servername AND DatabaseName = db_name()  
ORDER BY StartTime DESC;













2019年1月9日 星期三

SQL Server create alwayson with error 19456

env: Windows Server 2016
        SQL Server 2016 SP2
        SSMS 17.8

在架設SQL Server Alwayson,要建立AG出現以下訊息:
message:
None of the IP addresses configured for the availability group listener can be hosted by the server 'XXXXXX'. Either configure a public cluster network on which one of the specified IP addresses can be hosted, or add another listener IP address which can be hosted on a public cluster network for this server.

Failed to join local availability replica to availability group 'Ag-XXXXX'.  The operation encountered SQL Server error 19456 and has been rolled back.  Check the SQL Server error log for more details.  When the cause of the error has been resolved, retry the ALTER AVAILABILITY GROUP JOIN command. (.Net SqlClient Data Provider)














這讓我覺得莫名其妙,難道SSMS 17.8除了建立Database mirroring有bug,建立Alwayson也有bug?不對,用SSMS 17.8環境建這麼多Alwayson,怎麼可能。

所以在網路上找了一下相關訊息,發現比較常提的是
1.SQL Server服務帳號權限不足,例如沒有沒有寫入磁碟權限
2.SQL Server endpoint網路設定不對,port不通

以上兩點測試都沒有問題。Alwayson依舊一個有問題一個沒問題。

檢查後發現只有一個不一樣。沒錯,服務帳號
不是帳號不同,是格式不同,一個是: sqlserver@domain,另一個是:domain\sqlserver。

有問題的是:sqlserver@domain,把這個帳號格式改為:sqlserver@domain。Alwayson順利建立。


2019年1月6日 星期日

SQL Server speedup create index in alwayson

env: Windows Server 2106
        SQL Server 2016 SP2

SQL Server 2012開始推出Alwayson功能,這個功能強化原本Database Mirroring,做到讀寫分離的目的,但伴隨而來的是維護所引伴隨而來的Latency問題。
因此要在大資料的環境要加速索引的建置速度降低Alwayson latency時間。

我們測試的環境是單機的虛擬機,8 Cores,DB只有一個Data file。SQL Server有開啟Trace Flag 1117, 1118。
Trace Flag 1117:
當檔案群組中的某個檔案達到自動成長閾值時,檔案群組中的所有檔案都會成長。
注意: 從 SQL Server 2016 (13.x) 開始,此行為由 ALTER DATABASE 的 AUTOGROW_SINGLE_FILE 和 AUTOGROW_ALL_FILES 選項控制,追蹤旗標 1117 沒有任何作用。
Trace Flag 1118:
移除伺服器上大部分的單一頁面配置,以減少 SGAM 頁面的競爭情況。 建立新物件時,根據預設,前八頁會從不同的範圍 (混合範圍) 進行配置。 之後若需要更多頁面時,將會從相同的範圍 (統一範圍) 加以配置。 SGAM 頁面可用以追蹤這些混合範圍,因此若出現多個混合頁面配置,它會很快地成為瓶頸。 這個追蹤旗標會在建立新物件時,從相同的範圍配置所有八個頁面,進而將掃描 SGAM 頁面的需求降到最低。
注意: 從 SQL Server 2016 (13.x) 開始,此行為由 ALTER DATABASE 的 SET MIXED_PAGE_ALLOCATION 選項控制,追蹤旗標 1118 沒有任何作用。
DBCC TRACEON - Trace Flags (Transact-SQL)


1.環境1: TRACE FLAG 1117, 1118。8 Cores。Create Index with online。
command:
SET QUOTED_IDENTIFIER ON
SET STATISTICS PROFILE ON
CREATE NONCLUSTERED INDEX [IX_External] ON [dbo].[testtb01]
(
[External] DESC
)
INCLUDE ( [Id]) WITH (DATA_COMPRESSION = PAGE, Online=on)

GO

SET QUOTED_IDENTIFIER ON
CREATE NONCLUSTERED INDEX [IX_Aggregated] ON [dbo].[testtb01]
(
[Aggregated] DESC
)
INCLUDE ([Id]) WITH (DATA_COMPRESSION = PAGE, ONLINE=ON)
GO

結果:
執行次序
servername
db_date
table_name
idx_id
index_name
row_count
data_used_mb
Exec(Mins)
1
DBTEST01
DBTEST01
testtb01
18
IX_External
768101126
40078
56
2
DBTEST01
DBTEST01
testtb01
11
IX_Aggregated
768101126
46985
36

2.環境2: TRACE FLAG 1117, 1118。8 Cores。Create Index with online。
使用TempDB排序建立。
command:
SET QUOTED_IDENTIFIER ON
SET STATISTICS PROFILE ON
CREATE NONCLUSTERED INDEX [IX_External] ON [dbo].[testtb01]
(
[External] DESC
)
INCLUDE ( [Id]) WITH (DATA_COMPRESSION = PAGE, Online=ON, SORT_IN_TEMPDB=ON)

GO

SET QUOTED_IDENTIFIER ON
CREATE NONCLUSTERED INDEX [IX_Aggregated] ON [dbo].[testtb01]
(
[Aggregated] DESC
)
INCLUDE ([Id]) WITH (DATA_COMPRESSION = PAGE, ONLINE=ON, SORT_IN_TEMPDB=ON)
GO

結果:TempDB使用40GB,速度沒有明顯提升。可能環境沒有優化造成。
執行次序
servername
db_date
table_name
idx_id
index_name
row_count
data_used_mb
Exec(Mins)
1
DBTEST01
DBTEST01
testtb01
18
IX_External
768101126
40078
62
2
DBTEST01
DBTEST01
testtb01
11
IX_Aggregated
768101126
46985
38

3.環境3: TRACE FLAG 1117, 1118。8 Cores。Create Index with online。
這次追加Trace Flag 610
Trace Flag 610:
控制以最低限度方式插入索引資料表的行為。從 SQL Server 2016 開始不需要此追蹤旗標,因為預設會針對索引資料表開啟最低限度記錄功能。在 SQL Server 2016 中,當大量載入作業導致系統配置新的頁面時,如果符合最低限度記錄的其他所有先決條件,則依序填滿新頁面的所有資料列會以最低限度方式記錄。插入到現有頁面 (未配置新頁面) 以維持索引順序的資料列仍會完整記錄,這些是載入期間因頁面分割而移除的資料列。此外也必須開啟索引的 ALLOW_PAGE_LOCKS (預設為「開啟」) 以啟用最低限度記錄作業,因為配置期間需要頁面鎖定,也因此只會記錄頁面或範圍配置。

command:
SET QUOTED_IDENTIFIER ON
SET STATISTICS PROFILE ON
CREATE NONCLUSTERED INDEX [IX_External] ON [dbo].[testtb01]
(
[External] DESC
)
INCLUDE ( [Id]) WITH (DATA_COMPRESSION = PAGE, Online=on)

GO

SET QUOTED_IDENTIFIER ON
CREATE NONCLUSTERED INDEX [IX_Aggregated] ON [dbo].[testtb01]
(
[Aggregated] DESC
)
INCLUDE ([Id]) WITH (DATA_COMPRESSION = PAGE, ONLINE=ON)
GO


結果:建立索引時間降低,但是非常有限。
執行次序
servername
db_date
table_name
idx_id
index_name
row_count
data_used_mb
Exec(Mins)
1
DBTEST01
DBTEST01
testtb01
18
IX_External
768101126
40078
52
2
DBTEST01
DBTEST01
testtb01
11
IX_Aggregated
768101126
46985
32

4.環境4: TRACE FLAG 1117, 1118, 610。8 Cores。Create Index with online。
增加Update statistics 8000000 rows, 使用TempDB排序建立。
command:
Update Statistics花費3分36秒

SET QUOTED_IDENTIFIER ON
SET STATISTICS PROFILE ON
CREATE NONCLUSTERED INDEX [IX_External] ON [dbo].[testtb01]
(
[External] DESC
)
INCLUDE ( [Id]) WITH (DATA_COMPRESSION = PAGE, Online=ON, SORT_IN_TEMPDB=ON)
GO

SET QUOTED_IDENTIFIER ON
CREATE NONCLUSTERED INDEX [IX_Aggregated] ON [dbo].[testtb01]
(
[Aggregated] DESC
)
INCLUDE ([Id]) WITH (DATA_COMPRESSION = PAGE, ONLINE=ON, SORT_IN_TEMPDB=ON)
GO

結果:整體時間有明顯下降。
執行次序
servername
db_date
table_name
idx_id
index_name
row_count
data_used_mb
Exec(Mins)
1
DBTEST01
DBTEST01
testtb01
18
IX_External
768101126
40078
38
2
DBTEST01
DBTEST01
testtb01
11
IX_Aggregated
768101126
46985
34

5.環境5: TRACE FLAG 1117, 1118, 610。8 Cores。Create Index with online。
增加Update statistics 8000000 rows, 使用TempDB排序建立。
在建立索引後再執行一次 Update statistics

command:
Update Statistics花費3分56秒


SET QUOTED_IDENTIFIER ONSET STATISTICS PROFILE ON
CREATE NONCLUSTERED INDEX [IX_External] ON [dbo].[testtb01]
(
[External] DESC
)
INCLUDE ( [Id]) WITH (DATA_COMPRESSION = PAGE, Online=on)

GO

Update Statistics花費4分13秒

SET QUOTED_IDENTIFIER ON
CREATE NONCLUSTERED INDEX [IX_Aggregated] ON [dbo].[testtb01]
(
[Aggregated] DESC
)
INCLUDE ([Id]) WITH (DATA_COMPRESSION = PAGE, ONLINE=ON)
GO


結果:與執行一次Update statistics差不多,但是整體效益沒有提升。
執行次序
servername
db_date
table_name
idx_id
index_name
row_count
data_used_mb
Exec(Mins)
1
DBTEST01
DBTEST01
testtb01
18
IX_External
768101126
40078
38
2
DBTEST01
DBTEST01
testtb01
11
IX_Aggregated
768101126
46985
36

6.環境6: TRACE FLAG 1117, 1118, 610。8 Cores。Create Index with online。
降低Update statistics 4000000 rows
command:
Update Statistics花費3分12秒

SET QUOTED_IDENTIFIER ON
SET STATISTICS PROFILE ON
CREATE NONCLUSTERED INDEX [IX_External] ON [dbo].[testtb01]
(
[External] DESC
)
INCLUDE ( [Id]) WITH (DATA_COMPRESSION = PAGE, Online=on)

GO

SET QUOTED_IDENTIFIER ON
SET STATISTICS PROFILE ON
CREATE NONCLUSTERED INDEX [IX_Aggregated] ON [dbo].[testtb01]
(
[Aggregated] DESC
)
INCLUDE ([Id]) WITH (DATA_COMPRESSION = PAGE, ONLINE=ON)
GO


結果:整體效益沒有提升。
執行次序
servername
db_date
table_name
idx_id
index_name
row_count
data_used_mb
Exec(Mins)
1
DBTEST01
DBTEST01
testtb01
18
IX_External
768101126
40078
35
2
DBTEST01
DBTEST01
testtb01
11
IX_Aggregated
768101126
46985
38

7.環境7: TRACE FLAG 1117, 1118, 610。8 Cores。Create Index with online。
僅對Clister Index執行Update statistics 8000000 rows

command:
Update Statistics花費4秒

SET QUOTED_IDENTIFIER ON
SET STATISTICS PROFILE ON
CREATE NONCLUSTERED INDEX [IX_External] ON [dbo].[testtb01]
(
[External] DESC
)
INCLUDE ( [Id]) WITH (DATA_COMPRESSION = PAGE, Online=on)
GO

SET QUOTED_IDENTIFIER ON
SET STATISTICS PROFILE ON
CREATE NONCLUSTERED INDEX [IX_Aggregated] ON [dbo].[testtb01]
(
[Aggregated] DESC
)
INCLUDE ([Id]) WITH (DATA_COMPRESSION = PAGE, ONLINE=ON)
GO

結果:狀況變差了
執行次序
servername
db_date
table_name
idx_id
index_name
row_count
data_used_mb
Exec(Mins)
1
DBTEST01
DBTEST01
testtb01
18
IX_External
768101126
40078
60
2
DBTEST01
DBTEST01
testtb01
11
IX_Aggregated
768101126
46985
38


8.環境8: TRACE FLAG 1117, 1118, 610。8 Cores。Create Index with online。
僅對Clister Index執行Update statistics 2000000 rows
這次測試所引建立索引: IX_Aggregated

command:
Update Statistics花費27秒

SET QUOTED_IDENTIFIER ON
SET STATISTICS PROFILE ON
CREATE NONCLUSTERED INDEX [IX_External] ON [dbo].[testtb01]
(
[External] DESC
)
INCLUDE ( [Id]) WITH (DATA_COMPRESSION = PAGE, Online=on)
GO

結果:與測試環境7相似,需要1小時
執行次序
servername
db_date
table_name
idx_id
index_name
row_count
data_used_mb
Exec(Mins)
1
DBTEST01
DBTEST01
testtb01
18
IX_External
768101126
40078
59



9.環境9: TRACE FLAG 1117, 1118, 610。8 Cores。Create Index with online。
接續環境8,嘗試把系統overlapping統計資訊移除。

command:
DROP STATISTICS [dbo].[testtb01].[_WA_Sys_00000008_49C3F6B7]
DROP STATISTICS [dbo].[testtb01].[_WA_Sys_00000011_49C3F6B7]
DROP STATISTICS [dbo].[testtb01].[_WA_Sys_00000003_49C3F6B7]
DROP STATISTICS [dbo].[testtb01].[_WA_Sys_0000000E_49C3F6B7]

SET QUOTED_IDENTIFIER ON
SET STATISTICS PROFILE ON
CREATE NONCLUSTERED INDEX [IX_Aggregated] ON [dbo].[testtb01]
(
[Aggregated] DESC
)
INCLUDE ([Id]) WITH (DATA_COMPRESSION = PAGE, ONLINE=ON)
GO

結果:在"IX_Aggregated"表現沒有很大的差異
執行次序
servername
db_date
table_name
idx_id
index_name
row_count
data_used_mb
Exec(Mins)

2
DBTEST01
DBTEST01
testtb01
11
IX_Aggregated
768101126
46985
35


10.環境10: TRACE FLAG 1117, 1118, 610。8 Cores。Create Index with online。
依據環境8, 9的狀況,重新測試移除系統統計資訊,再Update statistics 4000000 rows

command:
DROP STATISTICS [dbo].[testtb01].[_WA_Sys_00000003_49C3F6B7]
DROP STATISTICS [dbo].[testtb01].[_WA_Sys_00000004_49C3F6B7]
DROP STATISTICS [dbo].[testtb01].[_WA_Sys_00000005_49C3F6B7]
DROP STATISTICS [dbo].[testtb01].[_WA_Sys_00000006_49C3F6B7]
DROP STATISTICS [dbo].[testtb01].[_WA_Sys_00000008_49C3F6B7]
DROP STATISTICS [dbo].[testtb01].[_WA_Sys_0000000C_49C3F6B7]
DROP STATISTICS [dbo].[testtb01].[_WA_Sys_0000000D_49C3F6B7]
DROP STATISTICS [dbo].[testtb01].[_WA_Sys_0000000E_49C3F6B7]
DROP STATISTICS [dbo].[testtb01].[_WA_Sys_00000011_49C3F6B7]

Update Statistics花費1分26秒

SET QUOTED_IDENTIFIER ON
SET STATISTICS PROFILE ON
CREATE NONCLUSTERED INDEX [IX_External] ON [dbo].[testtb01]
(
[External] DESC
)
INCLUDE ( [Id]) WITH (DATA_COMPRESSION = PAGE, Online=on)
GO

SET QUOTED_IDENTIFIER ON
SET STATISTICS PROFILE ON
CREATE NONCLUSTERED INDEX [IX_Aggregated] ON [dbo].[testtb01]
(
[Aggregated] DESC
)
INCLUDE ([Id]) WITH (DATA_COMPRESSION = PAGE, ONLINE=ON)
GO

結果:時間與環境3差不多。
執行次序
servername
db_date
table_name
idx_id
index_name
row_count
data_used_mb
Exec(Mins)
1
DBTEST01
DBTEST01
testtb01
18
IX_External
768101126
40078
41
2
DBTEST01
DBTEST01
testtb01
11
IX_Aggregated
768101126
46985
40

結論:
在環境沒有特別優化,特別是TempDB在比較慢的磁碟,並且要在Alwayson環境建立索引且有時間急迫行的狀況,可以參考做以下的步驟提升速度。
1.enable trace flag 610
2.update statistics 4000000 rows