Bir SQL Server Dizinini kasıtlı olarak nasıl parçalayabilirim?


9

Sadece bu bakım komut dosyalarını daha iyi anlamak için, ben bir SQL Server 2017 test veritabanında kasıtlı olarak kötü dizinler koşulları oluşturmak istiyorum? SQL Server Dizin ve İstatistik Bakımı

Dizin bütünlüğünden ödün vermenin veya dizin parçalanmasını artırmanın hızlı / otomatik bir yolu var mı? Bunu başarmak için bakabileceğim yararlı bir kaynak biliyor musunuz?


Tanımına bağlı olarak çirkin yukarı karışıklık isteyebilirsiniz dolgu faktörü değil karışıklık parçalanma yukarı olacak, ama bir küçültücü olacak etkileyecek olan kuyunun olarak
scsimon

3
Veritabanındaki bir dizin mi yoksa tüm dizinler mi istiyorsunuz? Tüm dizinler için istiyorsanız , veritabanınızı DBCC SHRINKDATABASE ([yourNONProdDB])
Kin Shah

Tüm db dizinleri mükemmel olurdu. @KinShah
mororo

Yanıtlar:


10

Hayal edebileceğim hızlı bir yol, UNIQUEIDENTIFIERbirincil anahtar olarak bir tablo oluşturmak ve çok sayıda rastgele değer eklemek. Bu, şu komut dosyası kullanılarak gerçekleştirilebilir:

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;

Bu milyon satır üretecektir.

Bunun NEWID()herhangi bir sıralamayı garanti etmediğini bilerek , SQL Server'ın tablodaki rastgele noktalara eklenmesi gerekecektir - bu birincil anahtarı parçalayacaktır.


1
Bu işe yaramaz veya en azından aşağıdakileri garanti etmez: SQL Server, dizine eklemeden önce satırları sıralayabilir (muhtemelen satır sayısı nedeniyle diske biriktirme). Parçalanmayı zorlamak için, SSMS'de birçok ayrı ek gerçekleştirmeniz gerekir: INSERT dbo.Tests (Id) SELECT NEWID(); GO 1000000;- bu daha fazla zaman alacaktır. Başka bir soru için birlikte takıldığım bir örnek için pastebin.com/SVLtiRnP adresine bakın . Değişken uzunluktaki satırların kullanılması ve rastgele güncellenmesi, daha verimli bir şekilde parçalanmaya neden olabilir mi?
David Spillett

3

Birkaç "Çirkin" dizin yapmak istedim, bu yüzden aşağıdakileri yaptım. İyi çalıştı

-- 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. 

1

Genellikle, dizin parçalanması tablo olduğunda Updateveya Insertişlem gerçekleştiğinde gerçekleşir.

Sorunu hızlı bir şekilde üretmek istiyorsanız (Dizin parçalanması), Indextest tablonuzda daha az bir hesap oluşturun fill factorve bu tabloda ağır Updateveya Insertişlem yapın. Bu komut dosyalarıyla çalışabilirsiniz ..


1

CRYPT_GEN_RANDOMBu cevapta yaptığım gibi de kullanabilirsiniz : Dizin Optimize Komut Dosyasında Filtre Şeması .

Verileri şu şekilde parçalamak için üzerinde bir dizine sahip sayısal bir sütuna ekleyebilirsiniz:

-- Fill with random integers to create fragmentation
INSERT INTO [ProdTable] (c1, c2) VALUES  (CRYPT_GEN_RANDOM(8000), 'filler');
GO 12800

Ayrıca, verileri güncelleyebilir veya ihtiyacınız olan şeyse sayı yerine bir dizeye dönüştürebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.