博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
sql truncate_SQL Truncate和SQL Delete语句的内部
阅读量:2509 次
发布时间:2019-05-11

本文共 9061 字,大约阅读时间需要 30 分钟。

sql truncate

This article gives you an insight into the SQL Truncate and SQL Delete commands behavior.

本文使您深入了解SQL截断和SQL删除命令的行为。

介绍 (Introduction)

In the article , we learned the difference between truncate and delete statements. You should go through this article before going further with this article.

在之间的区别一文中,我们了解了truncate和delete语句之间的区别。 在继续本文之前,您应该先阅读本文。

In this article, we will look at the following topics.

在本文中,我们将研究以下主题。

  • Can you Rollback a delete transaction and a truncate command?

    您可以回滚删除事务和截断命令吗?
  • Which one is faster, Truncate or Delete and why?

    截断或删除哪个更快,为什么?

回滚删除事务 (Rollback a delete transaction)

Let’s say you started two separate transactions – delete and truncate. Later, we want to roll back this transaction. We issued a rollback command for this.

假设您启动了两个单独的事务–删除和截断。 稍后,我们要回滚此事务。 为此,我们发出了回滚命令。

Now, a question for you – Does rollback command recovers data for both delete and truncate? You might think we cannot rollback a truncate statement. Let’s explore this practically.

现在,您遇到了一个问题– rollback命令是否同时恢复删除和截断的数据? 您可能会认为我们无法回滚截断语句。 让我们实践一下。

准备数据库环境 (Prepare a database environment)

Let’s create a new database [SQLShackDemo] for this article, along with a sample data table:

让我们为本文创建一个新的数据库[SQLShackDemo],以及一个示例数据表:

CREATE DATABASE SQLShackDemo;GOUSE SQLShackDemo;GOCREATE TABLE test(id     INT IDENTITY(1, 1),  [Name] VARCHAR(10));GOINSERT INTO test([Name])VALUES('SampleData');GO 10

We have 10 records in the test table for demo purposes:

测试表中有10条记录用于演示:

Sample data

We can use dynamic management view sys.dm_db_database_page_allocations(starting from SQL Server 2012) to list database pages belonging to the SQL table. This DMV takes the following arguments:

我们可以使用动态管理视图sys.dm_db_database_page_allocations(从SQL Server 2012开始)列出属于SQL表的数据库页面。 该DMV采用以下参数:

  • Database id: We can specify database id or use DB_ID() function to pass the current database id 数据库ID:我们可以指定数据库ID或使用DB_ID()函数传递当前数据库ID
  • Object id: This parameter takes object id we want to analyze. It is good to use OBJECT_ID(‘Object’) for automatically supplying this value 对象ID:此参数采用我们要分析的对象ID。 最好使用OBJECT_ID('Object')自动提供此值
  • The next two arguments are Index id and partition id. If we specify NULL values, it returns information about all indexes and partitions

    接下来的两个参数是索引ID和分区ID。 如果我们指定NULL值,它将返回有关所有索引和分区的信息
  • In the last argument, we can specify LIMITED or DETAILED values. Let’s use DETAILED as it gives additional information compared to the LIMITED option output

    在最后一个参数中,我们可以指定LIMITED或Detailed值。 让我们使用Detailed,因为它提供了与LIMITED选项输出相比的更多信息
SELECT allocated_page_file_id AS PageFID,        allocated_page_page_id AS PagePID,        allocated_page_iam_file_id AS IAMFID,        allocated_page_iam_page_id AS IAMPID,        object_id AS ObjectID,        index_id AS IndexID,        partition_id AS PartitionNumber,        rowset_id AS PartitionID,        allocation_unit_type_desc AS iam_chain_type,        page_type AS PageType,        page_level AS IndexLevel,        next_page_file_id AS NextPageFID,        next_page_page_id AS NextPagePID,        previous_page_file_id AS PrevPageFID,        previous_page_page_id AS PrevPagePIDFROM sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID('test'), NULL, NULL, 'DETAILED')WHERE is_allocated = 1;GO

Alternatively, we can use DBCC IND command as well and it returns almost the similar output:

另外,我们也可以使用DBCC IND命令,它返回几乎类似的输出:

DBCC IND('SQLShackDemo','test',1)

In the output, we can see two pages with PagePID 94 and 256:

在输出中,我们可以看到两个页面的页面PID为94和256:

  • PagePID 94: It is an IAM (Index Allocation Map) page. The IAM page has NULL values for IAMFID and IAMPID columns. PageType 10 denotes IAM page PagePID 94:这是一个IAM(索引分配图)页面。 IAM页的IAMFID和IAMPID列的值为NULL。 PageType 10表示IAM页面
  • PagePID 256: It is a data page. PageType 1 denotes a data page PagePID 256:这是一个数据页。 PageType 1表示数据页

Now, let’s begin a delete transaction using the begin transaction statement:

现在,让我们使用begin transaction语句开始删除事务:

USE SQLShackDemo;GOBEGIN TRANSACTION;DELETE FROM [dbo].[test];

Since we did not specify the WHERE clause in the delete statement, it removes all ten rows from the test table:

由于我们未在delete语句中指定WHERE子句,因此它将删除测试表中的所有十行:

begin transaction statement

Do not commit the transaction as of now. We use the undocumented function fn_dblog to read transaction logs. You can refer to this article, to go through this command in detail.

到目前为止,请勿提交事务。 我们使用未记录的函数fn_dblog读取事务日志。 您可以参考本文, 以详细了解此命令。

  • Note: You should be careful using this function in the production environment. Here, we are using it for demonstration purposes.

    注意:您应该在生产环境中小心使用此功能。 在这里,我们将其用于演示目的。

In the same query window with existing Begin SQL transaction, execute the following command of fn_dblog. This query filters the transaction logs for delete transaction ( defined as test1 in begin transaction statement):

在与现有Begin SQL事务相同的查询窗口中,执行以下fn_dblog命令。 此查询过滤用于删除事务的事务日志(在begin transaction语句中定义为test1):

USE SQLShackDemo;GOCHECKPOINT;BEGIN TRANSACTION Test1;DELETE FROM [dbo].[test];SELECT [Current LSN],        [transaction ID] tranID,        [end time] endTime,        AllocUnitId,        Description,        operation,        ContextFROM ::fn_dbLog(NULL, NULL)WHERE [Transaction ID] IN(    SELECT [Transaction ID]    FROM fn_dbLog(NULL, NULL)    WHERE [Transaction Name] = 'Test1');

SQL delete statement removes individual row and logs entry for each row in the transaction log. We removed 10 rows from the test table, and output also reflects LOB_DELETE_ROWS entry for an individual row. This LOP_DELETE_ROWS operation occurs for the delete statement. We can also see a total of 11 rows in the output of fn_dblog for this delete operation:

SQL delete语句删除单个行,并在事务日志中为每一行记录日志条目。 我们从测试表中删除了10行,并且输出还反映了单个行的LOB_DELETE_ROWS条目。 LOP_DELETE_ROWS操作发生在delete语句中。 我们还可以在fn_dblog的输出中看到此删除操作共有11行:

Output of fn_dblog for delete transaction

Execute the select statement in the same transaction, and it returns zero in the output:

在同一事务中执行select语句,并在输出中返回零:

Select count(*) from [dbo].[test];

Now, issue a rollback statement and check for the number of rows in the test table. It returns 10 rows in the output. It shows you can rollback a delete transaction:

现在,发出回滚语句并检查测试表中的行数。 它在输出中返回10行。 它显示您可以回滚删除事务:

Rollback transactionSelect count(*) from [dbo].[test];

check the records count after SQL delete

回滚截断事务 (Rollback a truncate transaction)

Now, we want to check whether we can rollback a truncate statement or not. For this demo, drop the test table and recreate it with the same 10 rows from the script shared above.

现在,我们要检查是否可以回滚截断语句。 对于此演示,删除测试表并使用上面共享的脚本中的相同10行重新创建它。

Once we have an environment ready, start a new transaction and truncate table from the following script:

一旦我们准备好环境,就可以开始新事务并从以下脚本截断表:

USE SQLShackDemo;GOBEGIN TRANSACTION;TRUNCATE TABLE [dbo].[test];

In the following query, we started a transaction T1 and filtered output of fn_dblog for that particular transaction:

在以下查询中,我们启动了事务T1并为该特定事务过滤了fn_dblog的输出:

USE SQLShackDemo;GOCHECKPOINTGoBEGIN TRANSACTION T1;TRUNCATE TABLE [dbo].[test];SELECT [Current LSN],        [transaction ID] tranID,        [end time] endTime,        AllocUnitId,        Description,        operation,        ContextFROM ::fn_dbLog(NULL, NULL)WHERE [Transaction ID] IN(    SELECT [Transaction ID]    FROM fn_dbLog(NULL, NULL)    WHERE [Transaction Name] = 'T1');

For SQL truncate, we do not get an entry for individual rows in the transaction log. It deallocates the extent, as shown below:

对于SQL截断,我们不会在事务日志中获得单个行的条目。 它取消分配范围,如下所示:

Let’s issue rollback transaction command and check records in a test table. We get our records back. Yes, it proves that we can rollback a SQL Truncate statement as well:

让我们发出rollback transaction命令并检查测试表中的记录。 我们得到我们的记录。 是的,它证明我们也可以回滚一条SQL Truncate语句:

Verify records

SQL Server minimizes logging for truncate. To prove this point, insert more records in the test table using the following query:

SQL Server最小化了截断的日志记录。 为了证明这一点,请使用以下查询在测试表中插入更多记录:

INSERT INTO test([Name])VALUES('SampleData');GO 90

We have 100 records in the test table. Now, check the transaction log records count for both truncate and delete operations using scripts specified above.

测试表中有100条记录。 现在,使用上面指定的脚本检查事务日志记录中的截断和删除操作计数。

  • Transaction log records for delete: 101

    用于删除的事务日志记录:101

  • Transaction log records for truncate: 12

    截断的事务日志记录:12

From the above screenshots, we can verify that as the record count increases in a table, transaction log record count also increases for delete statement. It does not change much for the truncate statement. Hence,we can see, it takes more time to delete records in comparison with truncate for a huge table. If we wish to remove all records from a table, we should use truncate because it is fast and minimize transaction log growth.

从上面的屏幕截图中,我们可以验证表中记录数的增加,对于delete语句,事务日志记录数的增加。 截断语句的变化不大。 因此,我们看到,与截断大型表相比,删除记录要花费更多的时间。 如果我们希望从表中删除所有记录,则应使用truncate,因为它速度快并且可以最大程度地减少事务日志的增长。

结论 (Conclusion )

In this article, we explored internals of the SQL Truncate and SQL Delete statement. It also shows the reason for a fasater execution of the truncate statement in comparison with the delete statement. You should use commands as per your requirements.

在本文中,我们探讨了SQL Truncate和SQL Delete语句的内部。 与delete语句相比,它还显示了执行fruner截断语句的原因。 您应该根据需要使用命令。

翻译自:

sql truncate

转载地址:http://kfiwd.baihongyu.com/

你可能感兴趣的文章
数组Array的API2
查看>>
为什么 Redis 重启后没有正确恢复之前的内存数据
查看>>
No qualifying bean of type available问题修复
查看>>
spfile
查看>>
Team Foundation Service更新:改善了导航和项目状态速查功能
查看>>
WordPress资源站点推荐
查看>>
android Manifest.xml选项
查看>>
Cookie/Session机制具体解释
查看>>
ATMEGA16 IOport相关汇总
查看>>
JAVA基础-多线程
查看>>
面试题5:字符串替换空格
查看>>
[Codevs] 线段树练习5
查看>>
Amazon
查看>>
component-based scene model
查看>>
Echart输出图形
查看>>
hMailServer搭建简单邮件系统
查看>>
从零开始学习jQuery
查看>>
Spring+SpringMVC+MyBatis深入学习及搭建(四)——MyBatis输入映射与输出映射
查看>>
opacity半透明兼容ie8。。。。ie8半透明
查看>>
CDOJ_24 八球胜负
查看>>