问题描述
|
我有一个未规范化的数据库:
disciplinabd.movies:
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,在这里我将规范来自disciplinabd的数据。
因此,我正在尝试执行以下查询:
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
它可以正常执行,但是我需要执行大量数据,例如disciplinabd.movies中的1400万行。
我的问题是:
有如何改善我的插入物?
完成后我可以插入诸如insert (1,1000) ...
之类的东西吗,我只需更改诸如insert( 1001,2000) ..
之类的值并继续。
我的意思是,是否有可能一点一点地在数据库中插入?
这样,如果连接断开,我可以避免回滚操作。
昨天,此插入查询运行了16个小时,然后连接中断,我丢失了所有工作。
更新
CREATE TABLE movie(
id INT PRIMARY KEY,title VARCHAR(400) NOT NULL,year INT
)
CREATE TABLE actor (
id INT PRIMARY KEY,name VARCHAR(250) NOT NULL,sex CHAR(1) NOT NULL
)
CREATE TABLE actor_character(
id INT PRIMARY KEY IDENTITY,character VARCHAR(1000)
)
CREATE TABLE movie_actor(
idMovie INT,idActor INT,idCharacter INT,CONSTRAINT fk_movie_actor_1 FOREIGN KEY (idMovie) REFERENCES movie(id) ON DELETE CASCADE ON UPDATE CASCADE,CONSTRAINT fk_movie_actor_2 FOREIGN KEY (idActor) REFERENCES actor(id) ON DELETE CASCADE ON UPDATE CASCADE,CONSTRAINT fk_movie_actor_3 FOREIGN KEY (idCharacter) REFERENCES actor_character(id) ON DELETE CASCADE ON UPDATE CASCADE,CONSTRAINT pk_movie_actor PRIMARY KEY (idMovie,idCharacter)
)
解决方法
您没有看到正在使用的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范围,则可以生成一个ID范围,但是方法将取决于您使用的特定数据库。
至于您最初关于如何提高性能的问题,我将从将子选择移到JOIN并确保actor_character中的索引正确开始。例如:
INTO labbd11..movie_actor(idMovie,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,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