私が持っているSQL Server 2017テストデータベースで意図的に不良インデックス条件を作成したいのですが、これらのメンテナンススクリプトをよりよく理解するためですか?SQL Serverのインデックスと統計のメンテナンス
インデックスの整合性を損なったり、インデックスの断片化を増やしたりする高速/自動の方法はありますか?これを達成するために私が調べることができる有用なリソースを知っていますか?
DBCC SHRINKDATABASE ([yourNONProdDB])
私が持っているSQL Server 2017テストデータベースで意図的に不良インデックス条件を作成したいのですが、これらのメンテナンススクリプトをよりよく理解するためですか?SQL Serverのインデックスと統計のメンテナンス
インデックスの整合性を損なったり、インデックスの断片化を増やしたりする高速/自動の方法はありますか?これを達成するために私が調べることができる有用なリソースを知っていますか?
DBCC SHRINKDATABASE ([yourNONProdDB])
回答:
簡単に想像できる1つの方法はUNIQUEIDENTIFIER
、主キーとしてを使用してテーブルを作成し、多数のランダムな値を挿入することです。これは、次のスクリプトを使用して実現できます。
CREATE TABLE dbo.Tests (Id UNIQUEIDENTIFIER PRIMARY KEY);
GO
INSERT INTO dbo.Tests (Id)
WITH x AS (SELECT n FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) v(n))
SELECT NEWID()
FROM x AS x1, x AS x2, x AS x3, x AS x4, x AS x5, x AS x6;
これにより、100万行が生成されます。
NEWID()
順序付けが保証されないことがわかっているため、SQL Serverはテーブル内のランダムなスポットに挿入する必要があります。これにより、主キーが断片化されます。
INSERT dbo.Tests (Id) SELECT NEWID(); GO 1000000;
-これには明らかに時間がかかります。別の質問のためにまとめた例については、pastebin.com / SVLtiRnPを参照してください。可変長の行を使用してランダムに更新すると、断片化がより効率的に発生する可能性がありますか?
「醜い」インデックスをいくつか作成したかったので、次のようにしました。うまくいきました
-- Create databases to test index job, each database is about 800MB with 100,000 GUID primary keys, in each of two tables
-- Create 6 database to test index job for DatabasesInParallel Database design based on example https://dba.stackexchange.com/q/9821/21924
--Drop last test
USE [master]
exec asp_kill_user_connections [IndexTest_1]
exec asp_kill_user_connections [IndexTest_2]
exec asp_kill_user_connections [IndexTest_3]
exec asp_kill_user_connections [IndexTest_4]
exec asp_kill_user_connections [IndexTest_5]
exec asp_kill_user_connections [IndexTest_6]
GO
DROP DATABASE [IndexTest_1]
GO
DROP DATABASE [IndexTest_2]
GO
DROP DATABASE [IndexTest_3]
GO
DROP DATABASE [IndexTest_4]
GO
DROP DATABASE [IndexTest_5]
GO
DROP DATABASE [IndexTest_6]
GO
-- create [IndexTest_1]
USE [master];
GO
CREATE DATABASE [IndexTest_1];
GO
USE IndexTest_1
SET NOCOUNT ON
CREATE TABLE TestGuidA (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
CREATE TABLE TestGuidB (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
DECLARE @BatchCounter INT = 1
DECLARE @Numrows INT = 100000
WHILE (@BatchCounter <= 20)
BEGIN
BEGIN TRAN
DECLARE @LocalCounter INT = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuidA (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @LocalCounter = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuidB (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @BatchCounter +=1
COMMIT
END
-----------------------------------------------
-- create [IndexTest_2]
USE [master];
GO
CREATE DATABASE [IndexTest_2];
GO
USE IndexTest_2
SET NOCOUNT ON
CREATE TABLE TestGuidA (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
CREATE TABLE TestGuidB (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
DECLARE @BatchCounter INT = 1
DECLARE @Numrows INT = 100000
WHILE (@BatchCounter <= 20)
BEGIN
BEGIN TRAN
DECLARE @LocalCounter INT = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuidA (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @LocalCounter = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuidB (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @BatchCounter +=1
COMMIT
END
------------------------------------
-- create [IndexTest_3]
USE [master];
GO
CREATE DATABASE [IndexTest_3];
GO
USE IndexTest_3
SET NOCOUNT ON
CREATE TABLE TestGuidA (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
CREATE TABLE TestGuidB (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
DECLARE @BatchCounter INT = 1
DECLARE @Numrows INT = 100000
WHILE (@BatchCounter <= 20)
BEGIN
BEGIN TRAN
DECLARE @LocalCounter INT = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuidA (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @LocalCounter = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuidB (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @BatchCounter +=1
COMMIT
END
----------------------------------------
-- create [IndexTest_4]
USE [master];
GO
CREATE DATABASE [IndexTest_4];
GO
USE IndexTest_4
SET NOCOUNT ON
CREATE TABLE TestGuidA (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
CREATE TABLE TestGuidB (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
DECLARE @BatchCounter INT = 1
DECLARE @Numrows INT = 100000
WHILE (@BatchCounter <= 20)
BEGIN
BEGIN TRAN
DECLARE @LocalCounter INT = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuidA (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @LocalCounter = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuidB (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @BatchCounter +=1
COMMIT
END
------------------------------------------------
-- create [IndexTest_5]
USE [master];
GO
CREATE DATABASE [IndexTest_5];
GO
USE IndexTest_5
SET NOCOUNT ON
CREATE TABLE TestGuidA (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
CREATE TABLE TestGuidB (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
DECLARE @BatchCounter INT = 1
DECLARE @Numrows INT = 100000
WHILE (@BatchCounter <= 20)
BEGIN
BEGIN TRAN
DECLARE @LocalCounter INT = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuidA (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @LocalCounter = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuidB (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @BatchCounter +=1
COMMIT
END
--------------------------------------------
-- create [IndexTest_6]
USE [master];
GO
CREATE DATABASE [IndexTest_6];
GO
USE IndexTest_6
SET NOCOUNT ON
CREATE TABLE TestGuidA (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
CREATE TABLE TestGuidB (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
DECLARE @BatchCounter INT = 1
DECLARE @Numrows INT = 100000
WHILE (@BatchCounter <= 20)
BEGIN
BEGIN TRAN
DECLARE @LocalCounter INT = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuidA (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @LocalCounter = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuidB (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @BatchCounter +=1
COMMIT
END
-------------------------------
use master
DBCC FREEPROCCACHE -- Clear plan cache for next text.
ある場合は通常、インデックスの断片化が起こるUpdate
か、Insert
操作がテーブルの上に起こります。
問題(インデックスの断片化)をすばやく生成したい場合Index
は、テストテーブルにを作成し、少ないテーブルでfill factor
重いテーブルUpdate
またはInsert
操作を実行します。これらのスクリプトで作業できます。
CRYPT_GEN_RANDOM
この回答で行ったように、インデックスオプティマイズスクリプトでのスキーマのフィルターを使用することもできます。
次のように、インデックスを持つ数値列にデータを挿入して、フラグメント化できます。
-- Fill with random integers to create fragmentation
INSERT INTO [ProdTable] (c1, c2) VALUES (CRYPT_GEN_RANDOM(8000), 'filler');
GO 12800
データが必要な場合は、データを更新するか、数値ではなく文字列に変換することもできます。