如何以编程方式在表之间传输大量数据?

时间:2011-04-12 18:07:19

标签: java sql-server database servlets

我有两张桌子,第一张桌子里有1400万张,第二张桌子里有150万张数据。

所以我想知道如何将这些数据传输到另一个表进行规范化? 我如何将某种类型转换为另一种类型,例如:我有一个名为'year'的字段,但它的类型是varchar,但我想要它是一个整数,我该怎么做?

我想过在java中循环使用JDBC,但我认为这不是很有效。

// 1.5 million of data
CREATE TABLE dbo.directorsmovies
    (
    movieid    INT NULL,
    directorid INT NULL,
    dname      VARCHAR (500) NULL,
    addition   VARCHAR (1000) NULL
    )

//14 million of data
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
    )

这是我的新表:

DROP TABLE actor
CREATE TABLE actor (
    id INT PRIMARY KEY IDENTITY,
    name VARCHAR(200) NOT NULL, 
    sex VARCHAR(1) NOT NULL
)

DROP TABLE actor_character
CREATE TABLE actor_character(
    id INT PRIMARY KEY IDENTITY,
    character VARCHAR(100)
)

DROP TABLE director
CREATE TABLE director(
    id INT PRIMARY KEY IDENTITY,
    name VARCHAR(200) NOT NULL,
    addition VARCHAR(150)
)


DROP TABLE movie
CREATE TABLE movie(
    id INT PRIMARY KEY IDENTITY,
    title VARCHAR(200) NOT NULL,
    year INT
)


DROP TABLE language
CREATE TABLE language(
    id INT PRIMARY KEY IDENTITY,
    language VARCHAR (100) NOT NULL
)

DROP TABLE genre
CREATE TABLE genre(
    id INT PRIMARY KEY IDENTITY,
    genre VARCHAR(100) NOT NULL
)

DROP TABLE director_movie
CREATE TABLE director_movie(
    idDirector INT,
    idMovie INT,
    CONSTRAINT fk_director_movie_1 FOREIGN KEY (idDirector) REFERENCES director(id),
    CONSTRAINT fk_director_movie_2 FOREIGN KEY (idMovie) REFERENCES movie(id),
    CONSTRAINT pk_director_movie PRIMARY KEY(idDirector,idMovie)
)

DROP TABLE genre_movie
CREATE TABLE genre_movie(
    idGenre INT,
    idMovie INT,
    CONSTRAINT fk_genre_movie_1 FOREIGN KEY (idMovie) REFERENCES movie(id),
    CONSTRAINT fk_genre_movie_2 FOREIGN KEY (idGenre) REFERENCES genre(id),
    CONSTRAINT pk_genre_movie PRIMARY KEY (idMovie, idGenre)
)

DROP TABLE language_movie
CREATE TABLE language_movie(
    idLanguage INT,
    idMovie INT,
    CONSTRAINT fk_language_movie_1 FOREIGN KEY (idLanguage) REFERENCES language(id),
    CONSTRAINT fk_language_movie_2 FOREIGN KEY (idMovie) REFERENCES movie(id),
    CONSTRAINT pk_language_movie PRIMARY KEY (idLanguage, idMovie)  
)

DROP TABLE movie_actor
CREATE TABLE movie_actor(
    idMovie INT,
    idActor INT,
    CONSTRAINT fk_movie_actor_1 FOREIGN KEY (idMovie) REFERENCES movie(id),
    CONSTRAINT fk_movie_actor_2 FOREIGN KEY (idActor) REFERENCES actor(id),
    CONSTRAINT pk_movie_actor PRIMARY KEY (idMovie,idActor)
)

更新: 我正在使用SQL Server 2008。 对不起,我忘了提及不同的数据库:

未规范化的是调用纪律字符和我的规范化调用imdb。

祝你好运, Valter Henrique。

3 个答案:

答案 0 :(得分:2)

如果两个表都在同一个数据库中,那么最有效的传输是在数据库中完成所有操作,最好是发送一个要在那里执行的SQL语句。

除非有理由只能在服务器外转换,否则应避免将数据从d / b服务器移动到其他地方然后再返回到d / b服务器。如果目的地是不同的服务器,那么这不是一个问题。

答案 1 :(得分:1)

虽然我的桌子与你的桌子相比相形见绌,但是我用存储过程解决了这个问题。对于MySQL,下面是我的脚本的简化(和未经测试)的本质,但类似的东西应该适用于所有主要的SQL基础。

首先,您应该添加一个新的整数年份列(示例中为int_year),然后使用以下过程迭代所有行:

DROP PROCEDURE IF EXISTS move_data;
CREATE PROCEDURE move_data()
BEGIN
  DECLARE done INT DEFAULT 0;
  DECLARE orig_id INT DEFAULT 0;
  DECLARE orig_year VARCHAR DEFAULT "";
  DECLARE cur1 CURSOR FOR SELECT id, year FROM table1;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

  OPEN cur1;

  PREPARE stmt FROM "UPDATE table1 SET int_year = ? WHERE id = ?";

  read_loop: LOOP
    FETCH cur1 INTO orig_id, orig_year;
    IF done THEN
      LEAVE read_loop;
    END IF;

    SET @year= orig_year;
    SET @id = orig_id;

    EXECUTE stmt USING @orig_year, @id;
  END LOOP;
  CLOSE cur1;
END;

要开始此过程,只需CALL move_data()

上面的SQL有两个主要的想法来加快它:

  1. 使用CURSORS迭代大表
  2. 使用PREPARED语句快速执行预先知道的命令
  3. PS。对于我的情况,这会加速从几岁到几秒钟,但在你的情况下,它仍然需要相当长的时间。所以最好从命令行执行,而不是从某些Web界面(例如PhpMyAdmin)执行。

答案 2 :(得分:1)

我刚刚为~150 Gb的数据做了这个。我为每个表使用了一对合并语句。第一个合并语句说“如果它不在目标表中,则将其复制到那里”,第二个说“如果它在目标表中,则从源中删除”。我把两个都放在while循环中,每次只执行10000行。将它保留在服务器上(而不是通过客户端传输)将对性能产生巨大的好处。试一试!