我有一个存储过程,它在几个表中插入一些记录。至少在几个表中,插入的记录数为 10000+。不过不超过15K。注意到3-5 mins这个程序来完成。也可以从多个用户会话中调用相同的过程,这会导致某些会话等待 20 分钟才能获得响应。我能做些什么来减少这个时间吗?
数据库恢复模式是完整的(无法更改),因此根据我的理解 sqlBulkCopy 在这里没有帮助。很想听听您对此的看法。
该表包含 15 列。其中5列是该表的外键。没有标识列,而是所有 5 个外键列组合的聚集索引。我在其他关键列上有几个索引。其余的列是十进制和 varchar(50)。不过我确实有一个 varchar(max) 列。
尝试获取查询或查询相同以供您参考。查询中最昂贵操作 (54) 的屏幕截图:
如果表的聚集索引是列组合而不是标识列,插入会受到影响吗?
基本上查询是'insert into this_table select from this table join with 5个其他表,这些表的主键是外键,以更新这些值。联接都在表之间的键上。我不介意发布查询,但是您是否还需要查询中涉及的所有表的架构?
EDIT2: 首先感谢你们所有人的回答、评论和想法。从中发生读取的对象结果是一个没有聚集索引的堆。修改它确实显着改善了读取操作,从而改善了整体。
我将 David Spillet 的答案标记为已接受,因为它提供了一种解决问题的有条理的方法。学到了一些关于发布问题的知识:)
也感谢飞盘的评论和回答。我知道我一直在修改问题:)
结构
1 个表名为:scan
2 列名为:id和date
问题
我有两个工作查询,一个 SELECT 和一个 INSERT,我想将它们合并在一起创建一个条件等于 0 的 INSERT。
查询1
如果数据库中最新的ID 行具有今天的扫描日期,则显示“1”,否则当不存在今天的日期时显示“0”。
SELECT
COUNT(scan.date) AS datecheck
FROM scan
WHERE scan.id = (SELECT
MAX(scan.id) AS datecheck
FROM scan
WHERE scan.date = CURDATE())
Run Code Online (Sandbox Code Playgroud)
查询2
如果今天没有条目,意味着结果为“0”,则创建一个包含 ID+1 和当前日期的新行。
INSERT INTO `scan`(`id`, `date`) SELECT (MAX(id)+1), CURDATE() FROM scan;
Run Code Online (Sandbox Code Playgroud)
我已经尝试了几个小时了,但还没有成功,如果您能告诉我哪里出了问题并让我知道正确的查询是什么,我将不胜感激。谢谢。
我正在开发一个具有将表格数据导出到指定数据库表的功能的应用程序。该应用程序使用INSERT语句将其数据导出到目标数据库。
插入是通过一个批处理INSERT语句完成的,每个 SQL 语句有 100 行INSERT(现在我不能使用BULK INSERT或bcp)。
我注意到,当源数据中的列数超过某个数字(该数字不是固定的,取决于值的大小、每个中的行数INSERT等)时,导出时间会不成比例地增加。
例如,导出 50 000 行(500 条INSERT语句,每条语句 100 行)的随机字符串,每个字符串有 100 个字符,每个INSERT需要100 行:
3 秒,5 列 6 秒,10 列 56 秒,15 列 77 秒,20 列
请注意 10 列和 15 列之间的导出时间差异。我原以为 15 列的导出时间为 9-10 秒,但实际上要长 5 倍。在测试其他数据集的导出时,我发现了类似的性能下降。
为了确保问题不在我这边,我INSERT通过sqlcmd.exe. 我得到了类似的结果。
问题:如何让 SQL Server 像处理小列一样快速处理大量列?或者至少将性能下降的点“移动”到更多的列?
额外细节:
INSERT 查询是在本地 SQL Server Express 2014(64 位)版本 12.0.5000.0 上执行的;我有一个查询,它将显示 SQL Server 中数据库表的记录的表名、行数和大小。当我执行查询时,我得到了一个结果显示
TableName NumberOfRows SizeinKB
TBL_PROCESS_AUDIT2 1 16
Run Code Online (Sandbox Code Playgroud)
但是当我使用相同的插入查询将更多记录插入同一个表并执行查询时,它显示更多的行数 (50) 但大小相同 (16kb)。
TableName NumberOfRows SizeinKB
TBL_PROCESS_AUDIT2 50 16
Run Code Online (Sandbox Code Playgroud)
实际上,当表的行数增加时,它的大小也应该增加。因此,对于 1 条记录,大小为 16KB,因此对于 50 条记录,大小应为 800KB。当我插入像大约 2000 条记录这样的批量记录时,大小会有所不同。
我的查询中的逻辑或问题是什么?我想要一个数据库表的记录的实际大小。
我的查询:
CREATE TABLE #RowCountsAndSizes (TableName NVARCHAR(128),rows CHAR(11),
reserved VARCHAR(18),data VARCHAR(18),index_size VARCHAR(18),
unused VARCHAR(18))
EXEC sp_MSForEachTable 'INSERT INTO #RowCountsAndSizes EXEC sp_spaceused ''?'' '
SELECT TableName,CONVERT(bigint,rows) AS NumberOfRows,
CONVERT(bigint,left(reserved,len(reserved)-3)) AS SizeinKB
FROM #RowCountsAndSizes
ORDER BY NumberOfRows DESC,SizeinKB DESC,TableName
DROP TABLE #RowCountsAndSizes
Run Code Online (Sandbox Code Playgroud) 所有语法都是有效的 PostgreSQL 作为 UPSERT 的示例,它返回字段的旧值和新值。比方说,我有一个表foo用(1,A)...(5,E)。
CREATE TEMP TABLE foo
AS
SELECT id, chr(id+64)
FROM generate_series(1,5) AS t(id);
CREATE UNIQUE INDEX ON foo(id);
id | chr
----+-----
1 | A
2 | B
3 | C
4 | D
5 | E
(5 rows)
Run Code Online (Sandbox Code Playgroud)
现在,假设我想要 UPSERT 6 行。一些碰撞,一些新的行。
SELECT id, chr(id+74)
FROM generate_series(3,8) AS t(id);
id | chr
----+-----
3 | M
4 | N
5 | O
6 | P
7 | Q
8 | R …Run Code Online (Sandbox Code Playgroud) 我有一个表 (Database2.dbo.OrganizerDataDependencyChange),其中包含有关某些其他表中的行上次更改时间的信息。在这些表中的每一个上,我都有一个触发器,它调用一个存储过程 (Database2.dbo.SaveOrganizerDataDependencyChange),该过程简单地用触发器触发的时间更新 Database2.dbo.OrganizerDataDependencyChange。这些触发器是从 Database1 或 Database2 触发的,因此它们通常是跨数据库调用。
当更新表上的两个不同行时,我在 Database1.dbo.OrganizerDataDependencyChange 表上遇到读写死锁,我不明白为什么。表上只有一个索引,而且它是完全覆盖查询的聚集索引,因此不可能出现查找死锁,尽管 proc 中有两条语句,但我特地将其重写为我所理解的最佳方法避免并发问题,使用 WHERE NOT EXISTS 而不是使用 IF/ELSE 逻辑,所以它不应该从不同的角度出现在这个索引上,对吗?由于它是在触发器和跨数据库中触发的,因此我在重现该问题时遇到了一些困难,我当然可以重现阻塞,但这应该没问题,这正是我所期望的。
有人可以帮助我了解这里发生了什么吗?我可能可以使用 NOLOCK 提示或 applock 修复它,但我仍然不明白为什么会发生这种情况。
这是表:
CREATE TABLE [dbo].[OrganizerDataDependencyChange](
[TableID] [INT] NOT NULL,
[Database] [VARCHAR](150) NOT NULL,
[Updated] [DATETIME] NULL
)
CREATE CLUSTERED INDEX [CX_OrganizerDataDependencyChange_TableID_DB] ON [dbo].[OrganizerDataDependencyChange]
(
[TableID] ASC,
[Database] ASC
)
Run Code Online (Sandbox Code Playgroud)
这是存储过程:
CREATE PROCEDURE [dbo].[SaveOrganizerDataDependencyChange]
(
@TableID int,
@Database varchar(150)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @rowcount INT;
INSERT INTO dbo.OrganizerDataDependencyChange
( TableID, [Database], Updated )
SELECT TOP …Run Code Online (Sandbox Code Playgroud) 我正在尝试运行一个脚本,该脚本一次将超过 2000 万条记录批量插入到 10,000 条表中。在运行开始时,它似乎工作正常。尽管一旦插入了大量记录(270,000),脚本的完成速度就开始变慢了。插入另外 30,000 条记录需要 23 小时。我最好的猜测是,随着新记录数量的增加,脚本检查新记录是否已经存在的部分需要更长的时间。我已经创建了脚本中使用的表的索引,但我需要为这个脚本缩短运行时间。任何帮助将非常感激。我的脚本如下。
CREATE NONCLUSTERED INDEX [plan2TMP] ON [dbo].[plan2]
(
[l_dr_plan1] ASC
)
INCLUDE
(
l_address,
l_provider
)ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [nameTMP] ON [dbo].[name]
(
[dr_id],
[nationalid]
)ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [plan1TMP] ON [dbo].[plan1]
(
[dr_id],
[cmt]
)ON [PRIMARY]
GO
DECLARE @BatchSize int = 10000
WHILE 1 = 1
BEGIN
INSERT INTO plan2(
l_dr_plan1
, l_address
, l_provider
)
SELECT TOP (@BatchSize)
dr1.link
,ad1.link
,dr.link
from plan1 dr1
INNER JOIN …Run Code Online (Sandbox Code Playgroud) 我们每秒从不同的平面文件导入多条记录。有时我们会遇到赛车条件,并重复唯一错误约束。我们正在插入和检索记录,
我听说有两种方法可以解决这个问题。这是更好的方法,我听说UPDLOCK,SERIALIZABLE是标准方法。但是,try catch 会阻止检查附加的 If 语句。两种方式都是完全证明,并且会停止重复插入吗?什么是最佳编码实践明智的,并且表现更好?
CREATE TABLE dbo.Customer
(
RowId bigint IDENTITY(1,1) NOT NULL,
CustomerId guid NOT NULL,
Name varchar(255) NOT NULL,
CONSTRAINT PK_RowId PRIMARY KEY CLUSTERED([RowId] ASC)
)
create unique nonclustered index [UN_CustomerId] ON [dbo].[Customer] ([CustomerId] ASC) include (Name)
create nonclustered index [UN_Name] ON [dbo].[Customer] ([Name] ASC) include (CustomerId)
Run Code Online (Sandbox Code Playgroud)
方法一:
IF NOT EXISTS
(
SELECT *
FROM dbo.Customer WITH (UPDLOCK, SERIALIZABLE)
WHERE Name = @Name
)
BEGIN
INSERT INTO dbo.Customer(CustomerId, Name) VALUES (@CustomerId, @Name)
SELECT @CustomerId
END
ELSE …Run Code Online (Sandbox Code Playgroud) 我有一个查询将数据从一个表插入到另一个表中。源列之一大于目标表的列,但查询中选择的实际数据并非如此。因此,例如,源表是varchar(25),目标表是varchar(10),并且查询为该特定列选择不超过 10 个字符的记录。
我的初始查询因截断错误而失败,但是当我重新编写它时,它选择了相同的记录但更改了 where 子句,即WHERE IN在 cte 上使用和过滤它成功运行。
即而不是做
select * from tbl where col1 = 1
Run Code Online (Sandbox Code Playgroud)
我做了:
with cte as (select 1) select * from tbl where col1 in (select 1 from cte)
Run Code Online (Sandbox Code Playgroud)
我知道这是 SQL Server 中的一个错误,但我仍然想知道 SQL Server 在哪一点验证插入的数据。在哪一点抛出错误?
我是数据库的新手,所以如果这是一个基本问题,请原谅我。
我试图解析一个复杂的开源字典,并将数据输出到一个同样复杂的 Access 数据库中:
我了解如何将数据插入到表中,但我不明白的是如何将数据插入到彼此依赖外键的多个表中。举个简单的例子:
我有三个表:Entry,Keyword,和Keyword_Priority。每个条目可以有多个关键字,因此该Keyword表Entry通过外键链接回。并且每个关键字元素可以有多个元素来描述关键字的优先级,因此该Keyword_Priority表Keyword通过外键链接回,如下所示:
在这个简化的场景中,假设我想使用 SQL 创建一个新条目。我从哪里开始?我:
先插入Entry表创建一个新的EntryID
然后Keyword使用新的EntryID作为外键插入到表中
然后Keyword_Priority使用关键字的ID字段作为外键插入到表中
或者,我应该反过来做吗...
插入Keyword_Priority表格
插入Keyword表格
插入Entry表格
总结一下,我的问题是:
一次将数据插入多个表时应该从哪里开始?自上而下,还是自下而上?
insert ×10
sql-server ×8
performance ×3
update ×2
bulk-insert ×1
concurrency ×1
deadlock ×1
logging ×1
ms-access ×1
mysql ×1
mysql-5.5 ×1
select ×1
upsert ×1