Как программно перенести много данных между таблицами? - PullRequest
3 голосов
/ 12 апреля 2011

У меня есть две таблицы, в первой из которых у меня 14 миллионов, а во второй - 1,5 миллиона данных.

Поэтому мне интересно, как я могу перенести эти данные в другую таблицу для нормализации?И как мне преобразовать один тип в другой, например: у меня есть поле с именем year, но его тип - varchar, но я хочу вместо него целое число, как мне это сделать?

Я думал осделать это с помощью JDBC в цикле, а из Java, но я думаю, что это неэффективно.

// 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.

С уважением, Вальтер Энрике.

Ответы [ 3 ]

2 голосов
/ 12 апреля 2011

Если обе таблицы находятся в одной и той же базе данных, то наиболее эффективный перенос - это сделать все это внутри базы данных, предпочтительно, отправив оператор SQL, который будет выполнен там.

Любое перемещение данных из dСледует избегать использования сервера / b в другом месте и затем возвращаться к серверу d / b, если только нет причины, по которой он может быть преобразован только вне сервера.Если местом назначения является другой сервер, то это гораздо менее важно.

1 голос
/ 12 апреля 2011

Я только недавно сделал это для ~ 150 Гб данных.Я использовал пару операторов слияния для каждой таблицы.Первый оператор слияния сказал: «если он не находится в таблице назначения, скопируйте его туда», а второй сказал «если он находится в таблице назначения, удалите его из источника».Я поместил оба в цикл while и сделал только 10000 строк в каждой операции за раз.Хранение его на сервере (а не передача через клиента) будет огромным благом для производительности.Дайте ему шанс!

1 голос
/ 12 апреля 2011

Хотя мои таблицы были карликами по сравнению с вашими, я однажды справился с такой проблемой с помощью хранимых процедур. Для 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. Использование курсоров для итерации по большой таблице
  2. Используйте оператор PREPARED для быстрого выполнения заранее известных команд

PS. для моего случая это ускорило вещи от веков до секунд, хотя в вашем случае это все еще может занять значительное количество времени. Поэтому, вероятно, лучше всего выполнять из командной строки, а не через какой-либо веб-интерфейс (например, PhpMyAdmin).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...