为什么第二个INSERT语句比第一个语句慢 5 倍?
从生成的日志数据量来看,我认为第二个不符合最小日志记录的条件。但是,数据加载性能指南中的文档指出两个插入都应该能够被最低限度地记录。因此,如果最小日志记录是关键性能差异,为什么第二个查询不符合最小日志记录?可以做些什么来改善这种情况?
查询 #1:使用 INSERT...WITH (TABLOCK) 插入 5MM 行
考虑以下查询,该查询将 5MM 行插入到堆中。此查询在 中执行1 second并生成64MB由 报告的事务日志数据sys.dm_tran_database_transactions。
CREATE TABLE dbo.minimalLoggingTest (n INT NOT NULL)
GO
INSERT INTO dbo.minimalLoggingTest WITH (TABLOCK) (n)
SELECT n
-- Any table/view/sub-query that correctly estimates that it will generate 5MM rows
FROM dbo.fiveMillionNumbers
-- Provides greater consistency on my laptop, where other processes are running
OPTION (MAXDOP 1)
GO
Run Code Online (Sandbox Code Playgroud)
查询 #2:插入相同的数据,但 SQL 低估了行数
现在考虑这个非常相似的查询,它对完全相同的数据进行操作,但碰巧从SELECT基数估计太低的表(或在我的实际生产案例中具有许多连接的复杂语句)中提取。此查询在事务日志数据中执行 …
performance sql-server insert transaction-log sql-server-2014
我试图了解提高客户给我的查询性能的最佳方法。它包含几个连接的表,其中一个被称为dwh.fac_sale_detail包含 15 亿行的表。
该表dwh.fac_sale_detail根据其名为 的列之一进行分区TradingDateKey1。它实际上以 yyyymmdd 格式存储数据,但它是INTDatatype。
这有从 2005 年到 2015 年的 TradingDateKeys,但分区只创建到 2014 年。
另一个团队中的一个人提出了以下建议,我正在尝试遵循他的建议,但我是创建或更改分区的新手,不知道这是否真的会对查询性能产生任何影响:
他用他自己的话来说是“该FactSalesDetail表目前大约有 15 亿行,目前TradingDate按年划分为 10 个分区,每个分区大约有 1.5 亿行。最好将最近一年进一步划分为月分区并在所有分区上应用列存储索引。在每个分区上应用索引将是一次性的,您应该只需要维护当前分区的索引。”
这是我尝试优化的查询的查询计划。
另请参阅随附的屏幕截图以更好地理解:
我有一个log带有ID标识列的表。多年来一切正常;然后,昨天,我在日志中看到以下错误:
该语句已终止。
违反 PRIMARY KEY 约束“PK__log__ID__3B40CD36”。无法在对象“dbo.log”中插入重复键。重复的键值为 (295992)。INSERT INTO log (datum, zeit, benutzer, modul, prozedur, code, zeile, bez1, bez2, tech_info) VALUES ('20151126 00:00:00.000', '19000101 18:26:45.121','Customer,', , '', 'WShop-Trans', 0, '1 Datensätze für Tabelle adresse gesendet.', '', '')
我检查了 IDENTITY 种子,看起来没问题:
查询:DBCC CHECKIDENT(log)
结果:正在检查身份信息:当前身份值“296021”,当前列值“296021”。
DBCC 执行完成。如果 DBCC 打印错误消息,请联系您的系统管理员。查询:SELECT MAX(ID) FROM 日志
结果:296021
表上没有触发器,也没有人弄乱种子值(我是管理数据库服务器的人,所以我很确定)。
到目前为止,这是一次性事件,我无法重现。
我看起来只是一个 SQL Server 故障,但我很好奇:这是一个已知的错误,还是对此有任何其他合理的解释?SQL Server 版本是Microsoft SQL Server 2012 - 11.0.2100.60 (X64).
为了完整起见,这里是完整的表脚本:
CREATE TABLE [log](
[datum] [datetime] NULL,
[ID] …Run Code Online (Sandbox Code Playgroud) 在我们不一定能确保预先排序的两个表中找到不同的行时,使用 aFULL OUTER JOIN而不是 a是个好主意UNION吗?这种方法有什么缺点吗?如果它始终更快,为什么查询优化器不为 UNION 选择FULL OUTER JOIN将使用的相同计划?
通过将 a 重写UNION为FULL OUTER JOIN. AUNION似乎是编写逻辑的更直观的方式,但在探索这两个选项时,我发现 A 的FULL OUTER JOIN内存和 CPU 使用率都更高。
如果您想运行我们的生产查询的简化和匿名版本,请参阅以下脚本:
安装脚本
-- Create a 500K row table
SELECT TOP 500000 ROW_NUMBER() OVER (ORDER BY NEWID()) AS id, v1.number % 5 AS val
INTO #t1
FROM master..spt_values v1
CROSS JOIN master..spt_values v2
-- Create a 5MM row table that will match some, but not all, …Run Code Online (Sandbox Code Playgroud)