我的数据库架构:
point
(point_id int PK, name varchar
); point_log
(point_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利用这一点,以避免树搜索成本?
答案 0 :(得分:0)
这似乎是一个很好的机会,可以通过其父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);
基本原理:在为给定point_log
point_log
条记录时,这会减少pointid
上的读取IO
此外,鉴于Sql Server将向非唯一聚簇索引添加4字节uniquifier,您也可以在群集中包含Surrogate PK,以使其唯一,即:
CREATE UNIQUE CLUSTERED INDEX C_PointLog ON dbo.Point_log(point_id, point_log_id);
如果每point_log_idx1 ( point_id asc, timestamp asc)
有point_logs
个point
,则需要保留非聚集索引point_log.pointid
,并且假设对point_log.timestamp
&放置的查询具有良好的选择性; {{1}}
答案 1 :(得分:0)
与物理写入磁盘和页面拆分和日志记录的成本相比,树搜索成本可能微不足道。
1)你绝对应该批量插入数据,而不是逐行插入数据。
2)为了减少point_log_idx1索引的页面拆分,您可以尝试在ORDER BY
语句中使用INSERT
。它仍然不能保证磁盘上的物理顺序,但它确实保证了生成point_log_id IDENTITY
的顺序,并且希望它将提示按此顺序处理源数据。如果以请求的顺序处理源数据,则point_log_idx1索引的b树结构可能会增长而不会产生不必要的高成本页面拆分。
我使用的是SQL Server 2008.我的系统可以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
或不使用INSERT
来衡量系统的效率。
您确实需要考虑INSERT
操作的性能以及后续查询的性能。
可能更快的插入会导致索引碎片更高,从而导致查询速度变慢。
因此,您应该在ORDER BY
之后使用{{1}}或不使用{{1}}来检查索引的碎片。
您可以使用sys.dm_db_index_physical_stats获取索引统计信息。
返回数据和索引的大小和碎片信息 SQL Server中指定的表或视图。