sql server 性能

介绍 (Introduction)

In this article, we will verify if the following statements are true or they are just myths:

在本文中,我们将验证以下陈述是正确的还是仅仅是神话:

  1. Truncate is faster than a delete and it consumes less space in the logs 截断比删除快,并且在日志中占用的空间更少
  2. Do not use cursors to Create or drop multiple objects because it is very slow 不要使用游标创建或删除多个对象,因为它非常慢
  3. Do not use cursors to convert or process row values because it is very slow 不要使用游标转换或处理行值,因为它非常慢

入门 (Getting started)

  1. Truncate is faster than a delete and it consumes less space in the logs 截断比删除快,并且在日志中占用的空间更少

    To delete all rows in a table, the best option is to use a truncate statement. This option is faster and consumes fewer system and log resources. But is it true?

    要删除表中的所有行,最好的选择是使用截断语句。 此选项更快,并且消耗更少的系统和日志资源。 但这是真的吗?

    We will test if that is true by creating a table with a million rows in two different databases. We will test the delete statement in one and in another; we will test the truncate statement.

    我们将通过在两个不同的数据库中创建具有一百万行的表来测试这是否成立。 我们将在另一个测试删除语句; 我们将测试截断语句。

    We will use the simple recovery model in the database to reduce the number of entries in the log.

    我们将使用数据库中的简单恢复模型来减少日志中的条目数。

    We will first create 2 databases:

    我们将首先创建2个数据库:

    create database deleteDemo

    创建数据库deleteDemo

    create database truncateDemo

    创建数据库truncateDemo

    These databases will be used to compare the results of the delete and truncate statements:

    这些数据库将用于比较delete和truncate语句的结果:

    Figure 0. 2 databases created图0. 2个数据库已创建

    The initial size is 16 MB for both databases (this value depends on the SQL Server version):

    两个数据库的初始大小均为16 MB(此值取决于SQL Server版本):

    Figure 1. Database size 图1.数据库大小

    We will set the recovery model to simple. This mode reduces the entries in the log. However, you cannot restore the database in a specific time with this option.

    我们将恢复模型设置为简单。 此模式将减少日志中的条目。 但是,您不能使用此选项在特定时间内还原数据库。

    In the Database Properties, go to Options and in Recovery model, select simple:

    在数据库属性中,转到选项,然后在恢复模型中选择简单:

    Figure 2. Recovery model图2.恢复模型

    You can also change the recovery model using T-SQL:

    您还可以使用T-SQL更改恢复模型:

    
    USE [master]
    GO
    ALTER DATABASE [deleteDemo] SET RECOVERY SIMPLE WITH NO_WAIT
    GOUSE [master]
    GO
    ALTER DATABASE [truncateDemo] SET RECOVERY SIMPLE WITH NO_WAIT
    GO

    In order to test the truncate and delete statements, we will create a table named myprices in each database with a million rows:

    为了测试截断和删除语句,我们将在每个数据库中创建一个名为myprices的表,该表具有一百万行:

    
    --Table truncateDemo
    Use truncateDemo
    GOwith listpricesas(select 1 id, CAST(RAND(CHECKSUM(NEWID()))*1000000 as int) pricesunion  allselect id + 1, CAST(RAND(CHECKSUM(NEWID()))*1000000 as int)  pricesfrom listpriceswhere id <= 1000000)select *into mypricesfrom listpricesOPTION(MAXRECURSION 0)--Table deleteDemo
    Use deleteDemo
    GOwith listpricesas(select 1 id, CAST(RAND(CHECKSUM(NEWID()))*1000000 as int) pricesunion  allselect id + 1, CAST(RAND(CHECKSUM(NEWID()))*1000000 as int)  pricesfrom listpriceswhere id <= 1000000)select *into mypricesfrom listpricesOPTION(MAXRECURSION 0)

    Note that the size of the database has increased from 16 MB to 144. This is because of the large number of rows inserted. The log file grows even with a Recovery Model set to simple:

    请注意,数据库的大小已从16 MB增加到144。这是因为插入了很多行。 即使将恢复模型设置为简单,日志文件也会增长:

    Figure 3. Database Size after inserting a million rows图3.插入一百万行后的数据库大小

    We will first test the delete statement:

    我们将首先测试delete语句:

    
    USE deleteDemo
    GO
    DELETE FROM [dbo].[myprices]

    As you can see, it takes 23 seconds to delete a million rows:

    如您所见,删除一百万行需要23秒:

    Figure 4. Time required to delete a million rows图4.删除一百万行所需的时间

    If we check the database properties, we will notice that the database size increased to 528 MB!

    如果我们检查数据库属性,我们将注意到数据库大小增加到528 MB!

    Figure 5. Database growth after deleting a million rows图5.删除一百万行后数据库的增长

    Now, we will try the truncate table statement:

    现在,我们将尝试截断表语句:

    
    USE truncateDemo
    GO
    TRUNCATE TABLE [dbo].[myprices]

    When you run truncate, the execution time is 0 seconds:

    当您运行truncate时,执行时间为0秒:

    Figure 6. Truncate execution time图6.截断执行时间

    If we check the log file, we notice that the database size did not change!

    如果我们检查日志文件,则会发现数据库大小没有改变!

    Figure 7. Database size after truncating图7.截断后的数据库大小

    As you can see, you save space and the execution time is better with truncate. If you need to delete all the rows, it is a must to use it.

    如您所见,您可以节省空间,并且使用truncate可以缩短执行时间。 如果需要删除所有行,则必须使用它。

  2. Do not use cursors Create or drop multiple objects because they are very slow 不要使用游标创建或删除多个对象,因为它们非常慢

    In the next example, we will show 2 ways to delete multiple SQL Server Objects. One using cursors and another using CTEs to generate statements. We will see which option is faster.

    在下一个示例中,我们将展示两种删除多个SQL Server对象的方法。 一个使用游标,另一个使用CTE生成语句。 我们将看到哪个选项更快。

    First, we will create 10000 tables using T-SQL:

    首先,我们将使用T-SQL创建10000个表:

    
    with ctesequenceas(select 1 idunion  allselect id + 1from ctesequencewhere id < 10000)select 'create table table'+cast(id as varchar(8))+'(id int)'from ctesequenceOPTION(MAXRECURSION 0) 

    This code will create the following T-SQL statements:

    此代码将创建以下T-SQL语句:

    
    Create table table1
    Create table table2
    Create table table3
    ….
    Create table table10000

    Copy and paste the 10,000 create table statementsstatements and execute them.

    复制并粘贴10,000个create table语句并执行它们。

    You will have 10,000 tables created.

    您将创建10,000个表。

    We will first create a cursor named delete_tables that will drop all the tables that start with the name table:

    我们将首先创建一个名为delete_tables的游标,该游标将删除所有以名称表开头的表:

    
    --create a cursor named delete_tables
    DECLARE delete_tables CURSOR FAST_FORWARD FOR
    --The query will show all the tables whose name starts with the word table
    SELECT [TABLE_NAME]
    FROM [INFORMATION_SCHEMA].[TABLES]
    WHERE [TABLE_NAME] like 'table%'
    OPEN delete_tables
    DECLARE @tablename varchar(30)
    FETCH NEXT FROM delete_tables into @tablename
    WHILE @@FETCH_STATUS <> -1
    BEGIN
    --we are dropping all the tables
    execute ('drop table '+@tablename )FETCH NEXT FROM delete_tables into @tablenameEND
    CLOSE delete_tables
    DEALLOCATE delete_tables
    GO

    The cursor will delete the 10,000 rows in 1 minute, 30 seconds:

    光标将在1分钟30秒内删除10,000行:

    Figure 8. Execution time 图8.执行时间

    We will try now another method to delete 1,000 tables. Create the 1,000 tables again and run these statements:

    现在,我们将尝试另一种删除1,000个表的方法。 再次创建1,000个表并运行以下语句:

     with ctesequenceas(select 1 idunion  allselect id + 1from ctesequencewhere id < 100000)select 'drop table table'+cast(id as varchar(8))from ctesequenceOPTION(MAXRECURSION 0)

    This sentence will generate 10,000 statements to drop 10,000 tables. Copy and paste them and finally execute them:

    这句话将生成10,000条语句以删除10,000个表。 复制并粘贴它们,最后执行它们:

    Figure 9. 10000 drop statements took 1 minute 15 seconds图9. 10000个drop语句花费了1分15秒

    In this example, we are running drop statements sequentially in both cases. Running without cursors is a little bit faster because of the locks and the where clause used in the cursors. However, it is not a big difference in this case. The advantage of using cursors is that you delete them at once and you do not need to copy and paste the drop statements.

    在此示例中,两种情况下我们都按顺序运行drop语句。 由于游标中使用了锁和where子句,因此没有游标的运行要快一些。 但是,在这种情况下,差别不大。 使用游标的优点是您可以一次删除它们,而无需复制和粘贴drop语句。

  3. Do not use cursors to convert or process row values because they are very slow 不要使用游标转换或处理行值,因为它们很慢

    In the last example, we will convert rows to a column separated by commas.

    在最后一个示例中,我们将行转换为以逗号分隔的列。

    For example, if we have a table like this:

    例如,如果我们有一个这样的表:

    ID 1 2 3

    ID 1 2 3

    We want to have the following result:

    我们希望得到以下结果:

    1,2,3

    1,2,3

    We will create a table with 1000 values named #mysequence:

    我们将创建一个包含1000个值的表,名为#mysequence:

    
    with ctesequenceas(select 1 idunion  allselect id + 1from ctesequencewhere id < 1000)select * into #mysequencefrom ctesequenceOPTION(MAXRECURSION 0)

    We will first try with cursors:

    我们将首先尝试使用游标:

    
    --Create a cursor
    DECLARE concatenate_values CURSOR FOR
    SELECT cast(id as varchar(30))
    FROM #mysequence
    OPEN concatenate_values
    DECLARE @value varchar(max)=''
    DECLARE @initialvalue varchar(8)=''
    FETCH NEXT FROM concatenate_values into @initialvalue
    WHILE @@FETCH_STATUS <> -1
    BEGIN
    --Concatenate the values
    SELECT @value= @value+','+@initialvalueFETCH NEXT FROM concatenate_values into @initialvalueEND
    CLOSE concatenate_values
    DEALLOCATE concatenate_values
    select @value

    The cursor will display the values separated by commas in 3 seconds:

    光标将在3秒内显示用逗号分隔的值:

    Figure 10. Cursor execution time 图10.游标执行时间

    We will now try to use something different from cursors. To verify the time we will set statistics and time to on in order to have the execution time in milliseconds (ms):

    现在,我们将尝试使用与游标不同的东西。 为了验证时间,我们将统计信息和时间设置为开,以使执行时间以毫秒(ms)为单位:

    
    SET STATISTICS io ON
    SET STATISTICS time ON
    GO

    We will first concatenate the values using a variable named @concatenatevalues and concatenate the values separated by commas:

    我们将首先使用名为@concatenatevalues的变量将这些值连接起来,并用逗号分隔这些值:

    
    declare @concatenatedvalues varchar(max)
    SET @concatenatedvalues = ''
    select @concatenatedvalues = @concatenatedvalues + cast(id as
    varchar(30))+ ',' from #mysequence
    select SUBSTRING(@concatenatedvalues, 0, LEN(@concatenatedvalues)) as
    [values]

    These queries will take less than 100 ms in average:

    这些查询平均需要不到100毫秒的时间:

    Figure 11. Execution time图11.执行时间

    Another option is to use the XML PATH, this option is shorter, easier to read, but it takes longer time:

    另一个选项是使用XML PATH,该选项更短,更易于阅读,但需要更长的时间:

    
    SELECT ',' + cast(id as varchar(30))
    FROM #mysequence
    FOR XML PATH('') 

    Figure 12. XML PATH solution图12. XML PATH解决方案

结论 (Conclusions)

In this article, we verified that truncate is more efficient that a delete statement. In our example, we verified that truncating 1 million rows does not fill the log file and it takes less than 1 second. By the other hand, we found that the delete statement increased the database size from 144 Mb to 528 Mb. In addition, the execution time to delete was 23 seconds.

在本文中,我们验证了截断比删除语句更有效。 在我们的示例中,我们验证了截断一百万行不会填充日志文件,并且花费了不到1秒的时间。 另一方面,我们发现delete语句将数据库大小从144 Mb增加到528 Mb。 另外,删除的执行时间为23秒。

第一次测试 (First test)

Statement Time (seconds) Growth Size in Mb
Truncate 0 0
Delete 23 384
声明 时间(秒) 增长量(兆)
截短 0 0
删除 23 384

Conclusion: When you need to delete all the rows, you should use Truncate.

结论:当需要删除所有行时,应使用Truncate。

第二次测试 (Second test)

In the second test, we dropped 10000 tables using cursors and then using CTE to generate the statements.

在第二个测试中,我们使用游标删除了10000个表,然后使用CTE生成了语句。

Cursors took 1 minute 30 seconds and CTE took 1 minute with 15 seconds.

游标花了1分钟30秒,CTE花了1分钟15秒。

Method Time (seconds)
Cursor 90
CTE 75
方法 时间(秒)
光标 90
CTE 75

The advantage of Cursors is that you can execute and delete the tables at once. In the CTE method, you need to generate the statements and after that, copy and paste the statements. The CTE code is simpler.

游标的优点是您可以一次执行和删除表。 在CTE方法中,您需要生成语句,然后复制并粘贴语句。 CTE代码更简单。

Conclusion: If you need to delete, create 100+ objects, using cursors is not a bad choice. Do not use Cursors if you can work with SETs of data.

结论:如果需要删除,使用光标创建100个以上的对象不是一个坏选择。 如果可以使用SET数据集,请不要使用Cursors。

第三次测试 (Third test)

In our third test, we converted 1000 rows into a single variable of 1000 values separated by commas.

在我们的第三个测试中,我们将1000行转换为1000个值的单个变量,并用逗号分隔。

We used 3 methods:

我们使用了3种方法:

  • Cursors 游标
  • Simple T-SQL 简单的T-SQL
  • T-SQL with XML PATH mode 具有XML PATH模式的T-SQL
Method Time (seconds)
Cursor 3
Simple T-SQL 0.06
T-SQL with XML PATH 0.3
方法 时间(秒)
光标 3
简单的T-SQL 0.06
具有XML PATH的T-SQL 0.3

Conclusion: When you need to update rows in a table, delete rows, insert or search values, using cursors isn’t a good idea. As you can see in this example, it is extremely slow.

结论:当您需要更新表中的行,删除行,插入或搜索值时,使用游标不是一个好主意。 如您在本例中所见,它非常慢。

XML PATH is commonly used in many scenarios to manipulate and modify row values to replace the cursors. However, there are sometimes faster solutions.

XML PATH通常在许多情况下用于操纵和修改行值以替换游标。 但是,有时会有更快的解决方案。

翻译自: https://www.sqlshack.com/sql-server-performance-myth-busters/

sql server 性能

sql server 性能_SQL Server性能神话破灭相关推荐

  1. sql server 性能_SQL Server硬件性能调整

    sql server 性能 SQL Server Performance Tuning can be a difficult assignment, especially when working w ...

  2. sql server 入门_SQL Server查询调整入门

    sql server 入门 This article will cover some essential techniques for SQL query tuning. Query tuning i ...

  3. sql server 面试_SQL Server审核面试问题

    sql server 面试 In this article, we will discuss a number of common and important SQL Server Audit que ...

  4. sql limit 子句_SQL Server TOP子句概述和示例

    sql limit 子句 This article explores the SQL Server TOP clause using various examples, along the way, ...

  5. sql数据透视_SQL Server中的数据科学:取消数据透视

    sql数据透视 In this article, in the series, we'll discuss understanding and preparing data by using SQL ...

  6. sql server 别名_SQL Server别名概述

    sql server 别名 This article gives an overview of SQL Server Alias and its usage for connecting with S ...

  7. 2008 r2 server sql 中文版补丁_SQL Server 2008 SP4 补丁

    SQL Server 2008 SP4 补丁对于客户而言,Microsoft SQL Server 2008 Service Pack 4 中的几个关键改进如下所示: 改进了从 SQL Server ...

  8. sql server 跟踪_SQL Server作业性能–跟踪

    sql server 跟踪 描述 (Description) Keeping track of our SQL Server Agent jobs is a very effective way to ...

  9. sql server作业_SQL Server作业性能–报告

    sql server作业 描述 (Description) Once collected, job performance metrics can be used for a variety of r ...

最新文章

  1. Web服务器 Web容器 Servlet容器
  2. 【风险管理】系统技术框架
  3. android 指定语言的资源,Android国际化多语言切换
  4. 双十一消费近万亿!1亿人见证数字物流,“尾款人”收货更快了?购物狂欢七大趋势浮现
  5. 测试学开发——第一课:环境搭建与页面开发介绍。
  6. php mysql查询出来二叉树的数据_tp框架怎么实现二叉树查询 如图,查询数据库中小明下面的所有人。到底下面多少人,不清楚。 代码如何实现...
  7. Machine Learning lectures- 机器学习课程
  8. 危险!请马上替换代码中的BeanUtils!!!
  9. rocketmq 消息删除_清空rocketmq消息方法
  10. 我怎梦想是计算机科学家,我的梦想是当一名科学家作文
  11. 运维:你们 JAVA 服务怎么又又又又出问题了!内存降不下来!
  12. JS正则验证输入框姓名只能输入中文和英文
  13. r语言mfrow全程_R语言(绘图入门)
  14. 详解 gRPC 客户端长连接机制实现
  15. 金融级实人认证是什么?
  16. 2022 CSP 游记
  17. ITK 形态学中的开运算和闭运算 腐蚀 膨胀
  18. win10的JDK安装环境变量配置
  19. NestJs 学习(一) 基础知识
  20. 智能时代,我们何去何从?

热门文章

  1. python reduce函数怎么用的_我如何仅通过使用reduce函数在python中创建单...
  2. python中参数的顺序和sys.argv顺序要一样么_Python中 sys.argv[]的用法简明解释
  3. 《构建之法》读后感二
  4. C# MVC Controller依赖注入的办法
  5. 软件设计开发思想总结
  6. 修改Jmeter中乱码问题
  7. 操作手机数据库的uri
  8. 今天终于辞职,投奔SoftBank
  9. vscode中断点调试nodejs实用方便
  10. Hybrid App开发设计与实现