web-dev-qa-db-ja.com

インデックスの断片化を手動で作成する

誰かがインデックスに特定の断片化を手動で作成するための良いアプローチを持っていますか?インデックス再構築のベンチマークの目的でこれが必要です。同じテーブル/インデックスの断片化率を特定するために必要な時間を測定するために、私が試したい特定の断片化レベルを再作成する必要があります。

多少ランダムなテーブルを更新してこの断片化を作成するのは非常に時間がかかり、困難です。何か案は?

更新:これは私のテストテーブルです。実際には約540K行あり、

USE [Test]
GO

/****** Object:  Table [dbo].[tFrag2]    Script Date: 12/22/2015 15:33:51 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[tFrag2](
    [a] [int] NULL,
    [b] [varchar](1000) COLLATE Latin1_General_CI_AS NULL,
    [c] [varchar](1000) COLLATE Latin1_General_CI_AS NULL,
    [d] [decimal](18, 0) NULL,
    [e] [int] NULL,
    [uid] [uniqueidentifier] NOT NULL,
    [dt1] [datetime] NULL,
    [dt2] [datetime] NULL,
    [dt3] [datetime] NULL,
    [dt4] [datetime] NULL,
    [dt5] [datetime] NULL,
    [dt6] [datetime] NULL,
    [dt7] [datetime] NULL,
    [dt8] [datetime] NULL,
    [dt9] [datetime] NULL,
    [nv1] [nvarchar](4000) COLLATE Latin1_General_CI_AS NULL,
    [nv2] [nvarchar](4000) COLLATE Latin1_General_CI_AS NULL,
    [nv8] [nvarchar](4000) COLLATE Latin1_General_CI_AS NULL,
    [nv3] [nvarchar](4000) COLLATE Latin1_General_CI_AS NULL,
    [nv4] [nvarchar](4000) COLLATE Latin1_General_CI_AS NULL,
    [nv5] [nvarchar](4000) COLLATE Latin1_General_CI_AS NULL,
    [nv6] [nvarchar](4000) COLLATE Latin1_General_CI_AS NULL,
    [nv7] [nvarchar](4000) COLLATE Latin1_General_CI_AS NULL,
    [lfd] [int] IDENTITY(1,1) NOT NULL,
 CONSTRAINT [PK_tFrag2] PRIMARY KEY CLUSTERED 
(
    [uid] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag2_a]  DEFAULT ((123123)) FOR [a]
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag2_b]  DEFAULT ('ccccccccccccccccccc4444444444444444444444444') FOR [b]
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag2_c]  DEFAULT ('ffffffffffffffffffffffffffffffffffffffffffffffff') FOR [c]
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag2_d]  DEFAULT ((7)) FOR [d]
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag2_e]  DEFAULT ((777)) FOR [e]
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag_uid2]  DEFAULT (newid()) FOR [uid]
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag2_dt1]  DEFAULT (getdate()) FOR [dt1]
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag2_dt2]  DEFAULT (getdate()) FOR [dt2]
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag2_dt3]  DEFAULT (getdate()) FOR [dt3]
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag2_dt4]  DEFAULT (getdate()) FOR [dt4]
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag2_dt5]  DEFAULT (getdate()) FOR [dt5]
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag2_dt6]  DEFAULT (getdate()) FOR [dt6]
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag2_dt7]  DEFAULT (getdate()) FOR [dt7]
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag2_dt8]  DEFAULT (getdate()) FOR [dt8]
GO

ALTER TABLE [dbo].[tFrag2] ADD  CONSTRAINT [DF_tFrag2_dt9]  DEFAULT (getdate()) FOR [dt9]
GO

ALTER TABLE [dbo].[tFrag2] ADD  DEFAULT ('xxxxxxxxxxxxxxxxxxxx') FOR [nv1]
GO

ALTER TABLE [dbo].[tFrag2] ADD  DEFAULT ('xxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxx') FOR [nv2]
GO

ALTER TABLE [dbo].[tFrag2] ADD  DEFAULT ('xxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxx') FOR [nv8]
GO

ALTER TABLE [dbo].[tFrag2] ADD  DEFAULT ('xxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxx') FOR [nv3]
GO

ALTER TABLE [dbo].[tFrag2] ADD  DEFAULT ('xxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxx') FOR [nv4]
GO

ALTER TABLE [dbo].[tFrag2] ADD  DEFAULT ('xxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxx') FOR [nv5]
GO

ALTER TABLE [dbo].[tFrag2] ADD  DEFAULT ('xxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxx') FOR [nv6]
GO

ALTER TABLE [dbo].[tFrag2] ADD  DEFAULT ('xxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxx') FOR [nv7]
GO
4
Magier

1つのインデックスでは、ありません。データベース内のインデックスについては、はい:テーブルを作成し、ループを実行して一連のレコードを作成し、データベースを拡張します。次に、テーブルをドロップします。次に、データファイルを圧縮します( ポールランダルによれば、非常に愚かです )。

3
DoubleVu

断片化は、ストレージエンジンが行を物理的に正しい論理位置に配置できない場合に発生します。したがって、内部スペースのないテーブルが必要であり、「中央」に行を挿入します。

ページを埋める最も簡単な方法は、1行だけが収まるようにすることです

create table T (
id int,                  -- primary key & clustered; fill factor 100%
c1 char (5000) not null  -- fixed length, over half the size of a page
)

必要な数の行を書き込みます。数十万人がそれを行うべきです。この段階での断片化を回避するために、IDを連続してください。ただし、新しい値にはギャップを残してください。

次に、行を挿入して、目的の断片化を実現します。現在の最小値と最大値の間のID値をランダムに生成します。これは反復的に行うことも、現在の行から上部nを選択して、予約されたギャップに合うようにIDをインクリメントすることにより、セットごとに行うこともできます。

ターゲット行数は、小さい初期セットから開始するか、行をランダムに削除することで達成できます。

0
Michael Green

私はすぐにこれをタイプしました...この吸盤は本当に機能しますが...遅いです。何かご意見は?

(dbo.FragStatは、このテーブルのフラグメント値を照会するビューです)

Create procedure dbo.fragIt
     @FragDest int = 10
as
SET Statistics IO OfF
SET Statistics Time OfF
SET nocount on

declare @fragPercent int = 0

declare @cntr int = 0
While @FragDest > @fragPercent 
Begin
    select @fragPercent = avg_fragmentation_in_percent from dbo.FragStat Where NameOfTable = 'tFrag2' AND ALLOC_unit_type_desc = 'IN_ROW_DATA'

    set @cntr = @cntr + DATEPART(MS, GETDATE()) + 1000
    Update tFrag2 SET nv1 = REPLICATE('X', 1000), nv2 = REPLICATE('Y', 1000), nv3 = REPLICATE('Y', 1000) 
    WHERE LFD = @cntr or LFD = @cntr + 135 OR LFD = @cntr + 240 OR LFD = @cntr + 545 OR LFD = @cntr + 657 OR LFD = @cntr + 784 OR LFD = @cntr + 854

End
print 'destination frag of ' + cast(@FragDest as varchar(3)) + ' reached: ' + cast(@fragPercent as varchar(3))
0
Magier