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