LINUX.ORG.RU

Импорт из MySQL в PostgreSQL


0

1

Crawler насобирал 1,647,385 записей в таблицу. Заметил MySQL начала тормозить. Хочу попробовать те же данные с PostgreSQL. Как импортировать? Не всё оказалось так просто как казалось. Дамп от mysqldump не подходит, пробовал с опциями --compact --compatibility=postgresql. Нашёл способ

mysql> select * from videos into outfile '/hui/hui';

b32=# \copy videos from '/hui/hui';

Однако возникла ошибка и ничего не поимпортировалось:

b32=# \copy videos from '/hui/hui';
ERROR:  literal carriage return found in data
HINT:  Use "\r" to represent carriage return.
CONTEXT:  COPY videos, line 1367997
b32=# select count(id) from videos;
     0

Что делать? Искать скриптом \r и замещать? Тогда наверное ещё надо учитывать внутри строки или нет. Возможно всплывут какие то другие специальные символы. Есть ли более автоматизированный универсальный способ?


1.5кк записей это не те объемы, врядле postgres тут поможет, проблема вероятно все же структуре БД. Какой тип нагрузки на таблицу и какой тип таблицы ?

hidden_4003
()
Ответ на: комментарий от hidden_4003

Количество данных будет продолжать расти. Заметил что тормоза появляются при ORDER BY created_on DESC, если же ORDER BY id DESC то намного быстрее:

mysql> explain SELECT videos.* FROM videos ORDER BY created_on DESC LIMIT 0, 30;
+----+-------------+--------+------+---------------+------+---------+------+---------+----------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows    | Extra          |
+----+-------------+--------+------+---------------+------+---------+------+---------+----------------+
|  1 | SIMPLE      | videos | ALL  | NULL          | NULL | NULL    | NULL | 1782405 | Using filesort |
+----+-------------+--------+------+---------------+------+---------+------+---------+----------------+
1 row in set (0.03 sec)

mysql> explain SELECT videos.* FROM videos ORDER BY id DESC LIMIT 0, 30;
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------+
|  1 | SIMPLE      | videos | index | NULL          | PRIMARY | 8       | NULL |   30 |       |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------+
1 row in set (0.00 sec)

mysql>

Добавление INDEX (created_on) не меняет ситуацию. Как можно оптимизировать?

tyler19
() автор топика
Ответ на: комментарий от hidden_4003

Только что обнаружил способ оптимизации. Оказывается MySQL может использовать только один INDEX per SELECT. Надо было добавить не просто INDEX (created_on) а INDEX created_on_id (created_on, id) причём именно в этой последовательности для быстрой работы ORDER BY created_on DESC, id DESC.

tyler19
() автор топика
Ответ на: комментарий от tyler19

Это не способ оптимизации это нормальный режим работы БД, таблица должна содержать индексы для быстрой работы.

В первом EXPLAIN видно что производилось полное сканирование таблицы type=ALL и сортировка на диске Using filesort. Также если соотношение запросов на чтение/запись близко к 50/50 то лучше использовать InnoDB для того чтобы избежать table lock.

hidden_4003
()
Ответ на: комментарий от hidden_4003

это нормальный режим работы БД
видно что производилось полное сканирование таблицы

Какой же это нормальный режим, если при наличии индекса производится полное сканирование. Это ненормальный движок СУБД, от которого надо избавляться пока записей не стало слишком много.

anonymous
()
Ответ на: комментарий от anonymous

Какой же это нормальный режим, если при наличии индекса производится полное сканирование. Это ненормальный движок СУБД, от которого надо избавляться пока записей не стало слишком много.

Я обращаю ваше внимание на:

В первом EXPLAIN видно что производилось

hidden_4003
()
Ответ на: комментарий от hidden_4003

Опять всё тормозит, добавил WHERE status = 'active'. Кто что подскажет:

CREATE TABLE `videos` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `site` varchar(255) NOT NULL,
  `site_id` bigint(20) unsigned NOT NULL,
  `site_url` varchar(255) NOT NULL,
  `title` text NOT NULL,
  `thumbnails` text NOT NULL,
  `duration_txt` varchar(32) NOT NULL,
  `duration` bigint(20) unsigned NOT NULL,
  `embed` text NOT NULL,
  `created_on` datetime NOT NULL,
  `status` enum('active','deleted') NOT NULL DEFAULT 'active',
  `views` bigint(20) unsigned NOT NULL DEFAULT '0',
  `rating` bigint(20) unsigned NOT NULL DEFAULT '0',
  `voted` bigint(20) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `site` (`site`),
  KEY `site_id` (`site_id`),
  KEY `site_url` (`site_url`),
  KEY `status` (`status`),
  KEY `id_created_on` (`id`,`created_on`),
  KEY `created_on_id` (`created_on`,`id`),
  KEY `in1` (`status`,`created_on`,`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1797527 DEFAULT CHARSET=utf8;

mysql> explain SELECT videos.* FROM videos WHERE status = 'active' ORDER BY created_on DESC, id DESC LIMIT 1782420, 30;
+----+-------------+--------+------+---------------+------+---------+-------+---------+-------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref   | rows    | Extra       |
+----+-------------+--------+------+---------------+------+---------+-------+---------+-------------+
|  1 | SIMPLE      | videos | ref  | status,in1    | in1  | 1       | const | 1782455 | Using where |
+----+-------------+--------+------+---------------+------+---------+-------+---------+-------------+
tyler19
() автор топика
Ответ на: комментарий от anonymous

Какой же это нормальный режим, если при наличии индекса производится полное сканирование. Это ненормальный движок СУБД, от которого надо избавляться пока записей не стало слишком много.

Думаю посмотреть на PostgreSQL, пожалуй напишу скрипт который берёт все записи из MySQL и вставляет туда одну за другой. Раньше не задумывался, т.к. не приходилось сталкиваться с таким объёмом данных. Теперь понимаю что MySQL действительно отстой.

tyler19
() автор топика
Ответ на: комментарий от tyler19

В документации PostgreSQL пишут:

The rows skipped by an OFFSET clause still have to be computed inside the server; therefore a large OFFSET can be inefficient.
С такими запросами как у Вас маловероятно что поможет, нужно разбивать данные на несколько таблиц либо менять запросы.

hidden_4003
()
Ответ на: комментарий от hidden_4003

Существует же полно сайтов с большими объёмами информации и работают вполне быстро. Как же оптимизировать? 7 секунд на единичный запрос это не дело.

tyler19
() автор топика
Ответ на: комментарий от hidden_4003

Элементарная же задача - все columns fixed size. Прибавить index * size и всё. Что же делать? Писать свою БД? Только что смотрел, занимает 3 минуты выборка с большим offset'ом.

tyler19
() автор топика
Ответ на: комментарий от tyler19

Note

Fixed-length row format is only available for tables without BLOB or TEXT columns. Creating a table with these columns with an explicit ROW_FORMAT clause will not raise an error or warning; the format specification will be ignored.

Явно не ваш случай.

hidden_4003
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.