SQL Server:如何改进插入查询?
我有一个未规范化的数据库: 电影:SQL Server:如何改进插入查询?,sql,sql-server,database,Sql,Sql Server,Database,我有一个未规范化的数据库: 电影: CREATE TABLE dbo.movies ( movieid VARCHAR (20) NULL, title VARCHAR (400) NULL, mvyear VARCHAR (100) NULL, actorid VARCHAR (20) NULL, actorname VARCHAR (250) NULL, sex CH
CREATE TABLE dbo.movies
(
movieid VARCHAR (20) NULL,
title VARCHAR (400) NULL,
mvyear VARCHAR (100) NULL,
actorid VARCHAR (20) NULL,
actorname VARCHAR (250) NULL,
sex CHAR (1) NULL,
as_character VARCHAR (1500) NULL,
languages VARCHAR (1500) NULL,
genres VARCHAR (100) NULL
)
我有我的数据库:labbd11,在那里我将规范化来自StripalAbd的数据。
所以我尝试执行这个查询:
INTO labbd11..movie_actor(idMovie, idActor, idCharacter)
SELECT CASE
WHEN IsNumeric(movies.movieid+ '.0e0') <> 1 THEN NULL
ELSE CAST (movies.movieid AS INT)
END,
CASE WHEN IsNumeric(movies.actorid+ '.0e0') <> 1 THEN NULL
ELSE CAST (movies.actorid AS INT)
END,
(SELECT id FROM actor_character WHERE character = movies.as_character)
FROM disciplinabd..movies
您没有看到正在使用的RDBMS,这可能有助于我们更准确地回答您的问题,但要回答第二个问题,您很可能可以限制SELECT查询以影响插入的数据量。比如说,
INSERT INTO labbd11..movie_actor(idMovie, idActor, idCharacter)
SELECT CASE
WHEN IsNumeric(movies.movieid+ '.0e0') <> 1 THEN NULL
ELSE CAST (movies.movieid AS INT)
END,
CASE WHEN IsNumeric(movies.actorid+ '.0e0') <> 1 THEN NULL
ELSE CAST (movies.actorid AS INT)
END,
(SELECT id FROM actor_character WHERE character = movies.as_character)
FROM disciplinabd..movies
WHERE movieid >= 1000 and movieid < 2000
如果没有连续的ID范围,则可能会生成一个,但该方法将取决于您使用的特定数据库
至于您关于如何提高性能的最初问题,我将首先将子选择移出到联接,并确保在actor_角色上有一个适当的索引。例如:
INTO labbd11..movie_actor(idMovie, idActor, idCharacter)
SELECT CASE
WHEN IsNumeric(movies.movieid+ '.0e0') <> 1 THEN NULL
ELSE CAST (movies.movieid AS INT)
END,
CASE WHEN IsNumeric(movies.actorid+ '.0e0') <> 1 THEN NULL
ELSE CAST (movies.actorid AS INT)
END,
actor_character.id
FROM disciplinabd..movies
LEFT JOIN disciplinabd..actor_characture ON movies.as_character = actor_characture.character
WHERE movieid >= 1000 and movieid < 2000
同样,如果您可以明确地说明您使用的是哪个数据库,我们可以提供更精确的答案。如果我写的是类似的东西,我不会期望1400万行在服务器级硬件上执行所需的时间超过几分钟。16个小时对于只插入1400万行来说似乎是一段非常长的时间。我不知道你的硬件是什么样的,所以我只回答手头的问题。对于1400万行,如果每1000行打开一个连接,速度会慢得多,所以我建议使用一个更可变的数字 如果可以的话,我还建议在movieid中添加一个索引
create nonclustered index IX_movies on movies(movieid)
您可以使用while循环来完成您要查找的内容
Declare @loopMax int,@bottomRange int,@topRange int,@rangeSize int
select @loopMax = MAX(movies.movieid) from disciplinabd..movies
set @rangeSize = @loopMax/20
set @bottomRange = 0
set @topRange = @rangeSize
while @topRange < @loopMax
begin
INSERT INTO labbd11..movie_actor(idMovie, idActor, idCharacter)
SELECT CASE
WHEN IsNumeric(movies.movieid+ '.0e0') <> 1 THEN NULL
ELSE CAST (movies.movieid AS INT)
END,
CASE WHEN IsNumeric(movies.actorid+ '.0e0') <> 1 THEN NULL
ELSE CAST (movies.actorid AS INT)
END,
actor_character.id
FROM disciplinabd..movies
LEFT JOIN actor_character ON movies.as_character = actor_character.character
WHERE movieid >= @bottomRange and movieid < @topRange
set @bottomRange = @topRange
set @topRange = @topRange + @rangeSize
end
labbd11..movie\u actor表的定义是什么?我本以为即使在我的笔记本电脑上插入1400万行数据类型int,int,int也不到一个小时。你有关于演员角色的索引吗。角色?我感觉硬件很差,如果把它连接到一个可能非常大的演员角色表中,可能会让本该花费很短时间的事情永远花掉。他将执行该查询1400万次。Valter你有查询计划吗?@JStead,我正在使用SQLDBX Personal作为客户端,我不确定它是否生成了查询计划JStead。@Martin,我在那里更新了我的帖子,它会告诉你我试图只存储电影的id、演员以及该电影中该演员的角色。将子选择移动到联接中可能会改变语义。它需要是一个外部连接,以保留纪律性中的行。不连接到任何演员角色的电影。一般来说,它还可能添加需要使用distinct删除的其他行,但我假设基数最多为1个匹配行,否则OP的原始查询将失败。OP是从dbo和isnumeric在SQL Server上运行的。移动到联接正是正确的做法,您将从逐行运行的内容更改为基于集合的解决方案,这就是为什么相关子查询不好的原因。我尝试运行SP,但它有问题。我更新了我的帖子,展示了我的表格,你能更新一下你的存储过程吗?试一试现在我有了一个不同的表名来命名actor_角色
Declare @loopMax int,@bottomRange int,@topRange int,@rangeSize int
select @loopMax = MAX(movies.movieid) from disciplinabd..movies
set @rangeSize = @loopMax/20
set @bottomRange = 0
set @topRange = @rangeSize
while @topRange < @loopMax
begin
INSERT INTO labbd11..movie_actor(idMovie, idActor, idCharacter)
SELECT CASE
WHEN IsNumeric(movies.movieid+ '.0e0') <> 1 THEN NULL
ELSE CAST (movies.movieid AS INT)
END,
CASE WHEN IsNumeric(movies.actorid+ '.0e0') <> 1 THEN NULL
ELSE CAST (movies.actorid AS INT)
END,
actor_character.id
FROM disciplinabd..movies
LEFT JOIN actor_character ON movies.as_character = actor_character.character
WHERE movieid >= @bottomRange and movieid < @topRange
set @bottomRange = @topRange
set @topRange = @topRange + @rangeSize
end