繁体   English   中英

将排序后的数据插入具有非聚集索引的表中

[英]Insert sorted data to a table with nonclustered index

我的数据库模式:

  • pointpoint_id int PK, name varchar );
  • point_logpoint_log_id int PK, point_id int FK, timestamp datetime, value int

point_log有一个索引:

point_log_idx1 (point_id asc, timestamp asc)

我需要将点日志样本插入到point_log表中,在每个事务中,仅插入一个point_id的日志样本,并且日志样本已经按升序排序。 这意味着事务中的所有日志样本数据的index( point_log_idx1)顺序都相同,我如何才能使SQL Server充分利用这一点,从而避免树搜索成本?

这看起来像改变聚集索引的好机会Point_Log其父集群point_id外键:

CREATE TABLE Point_log
( 
    point_log_id int PRIMARY KEY NONCLUSTERED, 
    point_id int, 
    timestamp datetime, 
    value int
);

接着:

CREATE CLUSTERED INDEX C_PointLog ON dbo.Point_log(point_id);

原理:在获取给定pointid point_log记录时,这将减少point_log上的读取IO

此外,鉴于Sql Server将向非唯一的聚集索引添加一个4字节的唯一化 ,您也可以在群集上也包括替代PK,以使其唯一,即:

CREATE UNIQUE CLUSTERED INDEX C_PointLog ON dbo.Point_log(point_id, point_log_id);

如果每个point都有很多point_logs ,并且假设对point_log.pointidpoint_log.timestamp筛选的查询具有良好的选择性,则需要保留非聚集索引point_log_idx1 ( point_id asc, timestamp asc)

与物理写入磁盘,页面拆分和日志记录的成本相比,树搜索的成本可以忽略不计。

1)您绝对应该批量插入数据,而不是逐行插入数据。

2)为了减少point_log_idx1索引的页面拆分,您可以尝试在INSERT语句中使用ORDER BY 它仍然不能保证磁盘上的物理顺序,但是可以保证将生成point_log_id IDENTITY的顺序,并希望它将提示以该顺序处理源数据。 如果按请求的顺序处理源数据,则point_log_idx1索引的b树结构可能会增长,而不会造成不必要的昂贵页面拆分。

我正在使用SQL Server2008。我有一个系统在24/7中央数据库中收集大量监视数据。 最初,我是逐行插入数据。 然后我意识到每个插入都是一个单独的事务,并且系统大部分时间都花在了写入事务日志中。

最终,我开始使用接受表值参数的存储过程来批量插入数据。 就我而言,一批是几百到几千行。 在我的系统中,我仅将数据保留给定的天数,因此我会定期删除过时的数据。 为了保持系统性能稳定,我还定期重建索引。

在您的示例中,它可能如下所示。

首先,创建一个表类型:

CREATE TYPE [dbo].[PointValuesTableType] AS TABLE(
    point_id int,
    timestamp datetime,
    value int
)

然后过程如下所示:

CREATE PROCEDURE [dbo].[InsertPointValues]
    -- Add the parameters for the stored procedure here
    @ParamRows dbo.PointValuesTableType READONLY
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    BEGIN TRANSACTION;
    BEGIN TRY

        INSERT INTO dbo.point_log
            (point_id
            ,timestamp
            ,value)
        SELECT
            TT.point_id
            ,TT.timestamp
            ,TT.value
        FROM @ParamRows AS TT
        ORDER BY TT.point_id, TT.timestamp;

        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION;
    END CATCH;

END

在实践中,无论使用ORDER BY还是不使用ORDER BY ,您都应该为系统测量更有效的方法。 您确实需要考虑INSERT操作的性能以及后续查询的性能。

更快的插入可能导致更高的索引碎片,从而导致更慢的查询。

因此,在使用ORDER BY或不使用ORDER BY INSERT之后,应该检查索引的碎片。 您可以使用sys.dm_db_index_physical_stats来获取索引统计信息。

返回SQL Server中指定表或视图的数据和索引的大小和碎片信息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM