以最少的停机时间重建空间索引

fre*_*ito 6 sql-server spatial sql-server-2014

我们刚刚从 SQL Server 2008 升级到 2014。除了我们在空间索引上遇到的问题之外,它进行得相当顺利。在这张桌子上,我们收到错误

无法在具有唯一索引“lu_unit__geolocation”的对象“sys.extended_index_1527780600_384000”中插入重复的键行。- 重复键值:(0x20330a3504, 95469304)。

空间索引不能有唯一约束,有问题。

我认为更安全的方法是重建索引。我做了一些实验,我发现在 160 万行上重建索引大约需要 50 秒。生产表大约有 550 万行,由于无法在线构建空间索引,因此在无法访问基表时至少需要 3 分钟。

有没有人有在最短的停机时间内重建空间索引的经验?我们可以用 30 秒但不能用 3 分钟。

Paw*_*ajs 3

该解决方案的概念是准备具有相同结构的数据副本,并使用 与原始表交换sp_rename。表结构的其他大变化也基本相同。

让我们创建表并用几何数据填充它。

CREATE TABLE SpatialTable (id int IDENTITY(1,1) primary key, geometry_col geometry);  
CREATE SPATIAL INDEX SIndx_SpatialTable_geometry_col1   
   ON SpatialTable(geometry_col)  
   WITH ( BOUNDING_BOX = ( 0, 0, 500, 200 ) ); 
GO

INSERT INTO SpatialTable (geometry_col)  
SELECT TOP 1000000 geometry::STGeomFromText('LINESTRING (100 100, 20 180, 180 180)', 0)
FROM sys.all_columns a,sys.all_columns b;
GO
Run Code Online (Sandbox Code Playgroud)

创建数据副本并准备适当的索引。这些操作不会损害原始表,并且除了空间索引创建之外应该很快。

SELECT * INTO SpatialTable2 FROM SpatialTable
GO

ALTER TABLE SpatialTable2 ADD CONSTRAINT PK_SpatialTable_Id PRIMARY KEY CLUSTERED (id); 
GO

CREATE SPATIAL INDEX SIndx_SpatialTable_geometry_col1   
   ON SpatialTable2(geometry_col)  
   WITH ( BOUNDING_BOX = ( 0, 0, 500, 200 ) ); 
GO
Run Code Online (Sandbox Code Playgroud)

现在让我们在基表上模拟一些插入。

INSERT INTO SpatialTable (geometry_col)  
SELECT TOP 1000 geometry_col FROM SpatialTable
Run Code Online (Sandbox Code Playgroud)

下面是一个只需要很短时间的技巧。

BEGIN TRANSACTION

    SET IDENTITY_INSERT dbo.SpatialTable2 ON

    INSERT INTO SpatialTable2 (id,geometry_col)  
    SELECT id,geometry_col FROM SpatialTable sp WITH (TABLOCKX)
    WHERE NOT EXISTS (SELECT ID FROM SpatialTable2 sp2 where sp2.id=sp.id)

    SET IDENTITY_INSERT dbo.SpatialTable2 OFF

    EXEC sp_rename 'dbo.SpatialTable', 'SpatialTable_old';
    EXEC sp_rename 'dbo.SpatialTable2', 'SpatialTable';

COMMIT TRANSACTION
Run Code Online (Sandbox Code Playgroud)

现在我们有了新表和新空间索引结构以及旧数据。当然,这只是步骤的建议,您应该将其应用于您的需求和数据结构,特别是更新和删除操作(如果它们发生在您的情况下)。

执行此操作后,您可以删除旧表以清理数据库或将其用于任何其他目的。