[英]Why are SQL server inserts so slow?
I'm trying to insert rows of in-memory data into a table on SQL Server Express 2005. It is running what seems to me very slowly - about 5 seconds per 1000 rows inserted. 我试图将内存中的数据行插入SQL Server Express 2005上的表中。对于我来说,它运行的速度非常慢-每插入1000行大约5秒。 I am just using a basic "INSERT INTO" command.
我只是在使用基本的“ INSERT INTO”命令。 The slowness does not depend on the table data - it is still slow with a table with one int column and no index.
慢速不取决于表数据-对于具有一个int列且没有索引的表,它仍然很慢。 It is nothing to do with my software - it is just as slow running SQL in a loop from Management Studio.
这与我的软件无关,它与Management Studio中循环运行的SQL一样慢。 There is nothing else accessing the database at the same time.
没有什么可以同时访问数据库了。 On a 3Ghz Xeon (old I know), this will take about 10 seconds to execute:
在3Ghz Xeon(我知道是旧的)上,执行此过程大约需要10秒:
declare @i int
set @i = 0
set nocount on
while @i < 2000
begin
insert into testdb(testcolumn)
values (1)
set @i = @i + 1
end
Is there a better way to insert bulk in-memory data than looping on INSERT? 有没有比在INSERT上循环更好的插入大容量内存数据的方法? Or some configuration I should change in SQL Server?
还是我应该在SQL Server中更改一些配置?
You perform each insert inside its own transaction. 您可以在自己的事务中执行每个插入操作。
Beginning and committing transaction is very expensive in SQL Server
. 在
SQL Server
开始和提交事务非常昂贵。
Enclose everything into a single transaction block: 将所有内容封装在一个事务块中:
declare @i int
set @i = 0
set nocount on
BEGIN TRANSACTION
while @i < 2000
begin
insert into testdb(testcolumn)
values (1)
set @i = @i + 1
end
COMMIT
To generate sample data, you can use a recursive CTE
: 要生成样本数据,可以使用递归
CTE
:
WITH q (num) AS
(
SELECT 1
UNION ALL
SELECT num + 1
FROM q
WHERE num < 2000
)
INSERT
INTO testdb(testcolumn)
SELECT 1
FROM q
OPTION (MAXRECURSION 0)
, which will be faster. ,这样会更快。
1) Log Flush on commit. 1)提交时记录刷新。 Every transaction has to ensure the log is flushed to the disk before the commit returns.
每个事务都必须确保在提交返回之前将日志刷新到磁盘。 Every INSERT statement is an implicit transaction.
每个INSERT语句都是一个隐式事务。 Bulk commit:
批量提交:
declare @i int
set @i = 0
set nocount on
begin transaction
while @i < 2000
begin
insert into testdb(testcolumn)
values (1)
set @i = @i + 1
if (@i % 1000 = 0)
begin
commit;
begin transaction;
end
end
commit
2) Slow disk. 2)磁盘慢。 Check the Avg.
检查平均 Disk sec/Transfer performance counter for your data and your log disks.
磁盘秒/传输性能计数器,用于您的数据和日志磁盘。
3) To many indices (unlikely on a test table). 3)许多索引(不太可能在测试表上)。 Each index is nearly as expensive as a 'table' for inserts.
每个索引几乎与插入的“表”一样昂贵。
4) Triggers (again, unlikely) 4)触发器(再次,不太可能)
Ultimately, measure. 最终,衡量。 Follow the guidelines of a whitepaper like Troubleshooting Performance Problems in SQL Server 2005 if you don't know where to start.
如果您不知道从哪里开始,请遵循白皮书的准则,例如对SQL Server 2005中的性能问题进行故障排除 。
You have plenty of tools/techniques to get more performance out of this type of work load. 您拥有大量的工具/技术,可以从此类工作负荷中获得更高的性能。
In addition to indices, if you're actual scenario is as per your example, you could do a set-based approach to insert 2000 records like this: 除了索引之外,如果您的实际情况符合您的示例,则可以执行基于集合的方法来插入2000条记录,如下所示:
INSERT testdb(testcolumn)
SELECT 1
FROM master..spt_values
WHERE number BETWEEN 1 AND 2000
Insert speed is driven by the following things: 插入速度受以下因素驱动:
In case it's of any interest, I go through this in detail in my book ( Ultra-Fast ASP.NET ), including benchmarks and example code. 如果有任何兴趣,我会在我的书( Ultra-Fast ASP.NET )中详细进行介绍,其中包括基准测试和示例代码。
Having a clustered index (usually primary key) actually increases insert speed, so verify you have one of those. 具有聚集索引(通常是主键)实际上可以提高插入速度,因此请确认您具有其中之一。 And running 1000 transactions against a table isn't the fastest way if you can have all of the data at once and insert it into the table (This can be accomplished by using table valued parameters in sql server 2008 or xml parameters in 2005).
如果可以一次拥有所有数据并将其插入到表中,那么对一个表运行1000个事务并不是最快的方法(这可以通过使用sql server 2008中的表值参数或2005年的xml参数来实现)。
I would google to "SQL Server Tuning"... There are many books written on the subject. 我会用谷歌搜索“ SQL Server Tuning” ...关于这个主题有很多书。 It is a very hard thing to solve as there are MANY things that affect speed, from query syntax, to RAM allocated to the server, to proportions of allocated RAM (to which part of SQL Server you allocate RAM), to RAID array configuration, and MANY other factors.
这是一件很难解决的事情,因为有很多因素会影响速度,从查询语法到分配给服务器的RAM,再到分配的RAM的比例(SQL Server分配RAM的那一部分),再到RAID阵列配置,和许多其他因素。 You can have a database server optimized for insert/updates (OLTP) or for querying (data warehouse type of stuff).
您可以使数据库服务器针对插入/更新(OLTP)或查询(东西的数据仓库类型)进行优化。 In other words, don't expect a single, simple answer to this, even thought your problem seems straightforward.
换句话说,即使您的问题看起来很简单,也不要期望对此有一个简单的答案。
This is why you have database server administrators. 这就是为什么您有数据库服务器管理员的原因。
Or you could just not sweat the server-side issues and optimize your client-code as much as possible, if timing is not very important to you. 或者,如果时间安排对您而言不是很重要,那么您可能就不会汗水服务器端问题并尽可能优化客户端代码。
I would look into prepared statements and transactions as a way to begin to optimize. 我将研究准备好的语句和事务作为开始进行优化的一种方式。 Then look at indexing (if this is a set of inserts that do not happen very often I would consider dropping indices, doing the import, and creating the indices again).
然后看一下索引(如果这是一组插入,但很少发生,我会考虑删除索引,进行导入,然后再次创建索引)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.