SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 27.07.2009 12:15:40

juni86
Участник
Зарегистрирован: 27.07.2009
Сообщений: 4

оптмизиация создания базы данных на более 10 млн записей

Добрый день.
у меня имеется текстовый файл объемом 22 Гб. Из него мне нужно извлечь все ссылки вида <a href="sense">lemma</a>, из чего нужно потом составить словарь, где каждой lemma будут соответствовать senses, на которые она ссылалась и количество таких ссылок. Т. е. нужно построить словарь, в котором перечисляются все возможные смыслы (ссылки) соответствующие каждой лемме (видимой части ссылки) и указывается их количество. По предварительным подсчетам будет не менее 15 миллионов записей.
Для доступа к MySql я использую JDBC.
Структура базы данных следущая:
1) Таблица лемм (lemmas)
+----------+----------------+------+-----+---------+----------------+
| lemma_id | int(11)        | NO   | PRI | NULL    | auto_increment |
| lemma    | varbinary(255) | YES  | UNI | NULL    |                |
| rate     | int(11)        | YES  |     | NULL    |                |
+----------+----------------+------+-----+---------+----------------+
2) Таблица смыслов (senses)
+----------+----------------+------+-----+---------+----------------+
| Field    | Type           | Null | Key | Default | Extra          |
+----------+----------------+------+-----+---------+----------------+
| sense_id | int(11)        | NO   | PRI | NULL    | auto_increment |
| sense    | varbinary(255) | YES  | UNI | NULL    |                |
+----------+----------------+------+-----+---------+----------------+
3) Собственно словарь (dictionary)
| Field    | Type    | Null | Key | Default | Extra |
+----------+---------+------+-----+---------+-------+
| lemma_id | int(11) | NO   | PRI |         |       |
| sense_id | int(11) | NO   | PRI |         |       |
| quantity | int(11) | YES  |     | NULL    |       |
+----------+---------+------+-----+---------+-------+

Данные я заполняю следующим образом:
1) Создаю кэш - хеш-таблицу в оперативке, в которой содержится словарь. Когда свободной памяти становится меньше, чем 0.4 от той, что было выделено изначально для процесса, я начинаю записывать хеш в бд.
2) Создаю батч, в котором заполняются таблицы лемм и смыслов (простой INSERT IGNORE DUPLICATES). Выполняю executeBatch().
3) Для всех пар лемма-смысл, что хранятся в кэше в текстовом виде, извлекаю их id из соответствующих таблиц. Формирую батч для заполнения словаря.
4) Выполняю батч для заполнения словаря.

Шаг 3, естественно, самый трудоемкий. Есть ли шанс как-то ускорить дело? Разумна ли подобная организация таблиц/запросов или лучше изменить структуру БД?

Спасибо заранее за помощь.

Неактивен

 

#2 27.07.2009 15:54:42

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: оптмизиация создания базы данных на более 10 млн записей

Структура вполне нормальная, не думаю, что будут с ней какие-то проблемы. Если хотите немного
увеличить скорость занесения данных, можете временно отключить индексы на таблицах
(ALTER TABLE tablename DISABLE INDEX); при этом потеряется проверка уникальности (временно),
но если Ваша программа и так следит за этим, то проблем быть не должно.

Неактивен

 

#3 27.07.2009 16:13:44

juni86
Участник
Зарегистрирован: 27.07.2009
Сообщений: 4

Re: оптмизиация создания базы данных на более 10 млн записей

Спасибо за ответ. Буду знать, что хотя бы со структурой у меня все в порядкеsmile

К сожалению, моя программа-заполнитель не может следить за проверкой уникальности. На данный момент она обработала 10 из 20 Гб и лемм у меня 10 652 384, а смыслов 9 899 298, я не могу держать это все в оперативной памяти, чтобы сверяться, потому что мне придется чаще очищать кэш, а следовательно чаще придется повторять шаг 3, а именно "Для всех пар лемма-смысл, что хранятся в кэше в текстовом виде, извлекаю их id из соответствующих таблиц."  На последней итерации (когда у меня в сумме 20 миллионов лем и смыслов) это заняло 4 часа.
Мне очень не нравится этот шаг 3. Мне очень интересно, можно ли как-то оптимизировать нижеследующее?

///Делаю PreparedStatement:
java.sql.PreparedStatement statement = conn.prepareStatement("select senses.sense_id, lemmas.lemma_id from senses, lemmas where senses.sense=? and lemmas.lemma=?;");

***
//в цикле вытаскиваю из хеш таблицы смысл - szSense и лемму - szLemmaRaw и отправляю их в PreparedStatement
statement.setString(1, szSense);
statement.setString(2, szLemmaRaw);
try {
    //выполняю PreparedStatement
    rs = statement.executeQuery();
   

      //получаю id леммы и смысла
    rs.next();
    int nSenId = rs.getInt("senses.sense_id");
    int nLemId = rs.getInt("lemmas.lemma_id");
   
       //формирую команду для их внесения в словарь, где nQuantity - сколько раз лемма встретилась в данном смысле (инициализуется выше, это не суть важно)
    stDictUpdate.addBatch("INSERT INTO dictionary(lemma_id,sense_id,quantity) VALUES ('"+nLemId+"','"+nSenId+"','"+nQuantity+"')" +
                                "ON DUPLICATE KEY UPDATE quantity=quantity+"+nQuantity +";");
    }
catch (SQLException e) {
    System.out.println("[INFO] Error on lemma: "+szLemma);
    e.printStackTrace();   
}
****

// после окончания цикла выполняю батч
stDictUpdate.executeBatch();
conn.commit();
stDictUpdate.clearBatch();
stDictUpdate.close();

Неактивен

 

#4 27.07.2009 20:53:07

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: оптмизиация создания базы данных на более 10 млн записей

Честно говоря, не понял Ваш алгоритм. Конкретно — откуда берется nQuantity. Если вставлять
приходится все равно построчечно, то я бы сделал вообще хранимую процедуру вставки, которая
бы занималась всей необходимой работой на стороне сервера, а программа бы упростилась до
тупого запуска процедуры на каждую подходящую под регулярное выражение строку.

Процедуру какую-то такую

CREATE PROCEDURE INSERT (l VARCHAR(50), s VARCHAR(50))
BEGIN
  INSERT IGNORE lemmas (lemma) VALUES (l);
  INSERT IGNORE senses (sense) VALUES (s);

  INSERT dictionary
  SELECT lemmas.id, senses.id, 1
  FROM lemmas, senses
  WHERE lemmas.lemma = l AND senses.sense = s
  ON DUPLICATE KEY UPDATE quantity = quantity + 1;
END


Работать будет не очень быстро, но не сильно медленнее отдельных SELECT-INSERT ов.

Неактивен

 

#5 27.07.2009 21:06:06

juni86
Участник
Зарегистрирован: 27.07.2009
Сообщений: 4

Re: оптмизиация создания базы данных на более 10 млн записей

nQuantity - количество одинаковых пар лемма-смысл. т.е. в процедуре тогда будет написано

WHERE lemmas.lemma = l AND senses.sense = s
  ON DUPLICATE KEY UPDATE quantity = quantity + nQuantity;
.

Спасибо Вам за совет, попробую с процедурой.

Отредактированно juni86 (27.07.2009 21:06:29)

Неактивен

 

#6 27.07.2009 21:22:13

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: оптмизиация создания базы данных на более 10 млн записей

Ну вот из Вашего куска кода просто совсем не понятно, откуда это число возникает smile

Неактивен

 

#7 27.07.2009 21:24:03

juni86
Участник
Зарегистрирован: 27.07.2009
Сообщений: 4

Re: оптмизиация создания базы данных на более 10 млн записей

Хотелось просто привести выдержки только из тех мест, где явно идет работа с MySql, вот оно и потерялосьsmile

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson