Как изменить UPDATE через SELECT - PullRequest
4 голосов
/ 18 декабря 2011

У меня есть такая структура моего БД:

CREATE TABLE IF NOT EXISTS `peoples` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

Для клиентов.

CREATE TABLE IF NOT EXISTS `peoplesaddresses` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `people_id` int(10) unsigned NOT NULL,
  `phone` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
  `address` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

Для своих адресов.

CREATE TABLE IF NOT EXISTS `peoplesphones` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `people_id` int(10) unsigned NOT NULL,
  `phone` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
  `address` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

Для своих телефонов.

UPD4

ALTER TABLE peoplesaddresses DISABLE KEYS; 
ALTER TABLE peoplesphones DISABLE KEYS; 

ALTER TABLE peoplesaddresses ADD INDEX i_phone (phone);
ALTER TABLE peoplesphones ADD INDEX i_phone (phone);
ALTER TABLE peoplesaddresses ADD INDEX i_address (address);
ALTER TABLE peoplesphones ADD INDEX i_address (address);

ALTER TABLE peoplesaddresses ENABLE KEYS;
ALTER TABLE peoplesphones ENABLE KEYS;

END UPD4

CREATE TABLE IF NOT EXISTS `order` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `people_id` int(10) unsigned NOT NULL,
  `name` varchar(255) CHARACTER SET utf8 NOT NULL,
  `phone` varchar(255) CHARACTER SET utf8 NOT NULL,
  `adress` varchar(255) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=12 ;

INSERT INTO `order` (`id`, `people_id`, `name`, `phone`, `adress`) VALUES
(1, 0, 'name1', 'phone1', 'address1'),
(2, 0, 'name1_1', 'phone1', 'address1_1'),
(3, 0, 'name1_1', 'phone1', 'address1_2'),
(4, 0, 'name2', 'phone2', 'address2'),
(5, 0, 'name2_1', 'phone2', 'address2_1'),
(6, 0, 'name3', 'phone3', 'address3'),
(7, 0, 'name4', 'phone4', 'address4'),
(8, 0, 'name1_1', 'phone5', 'address1_1'),
(9, 0, 'name1_1', 'phone5', 'address1_2'),
(11, 0, 'name1', 'phone1', 'address1'),
(10, 0, 'name1', 'phone1', 'address1');

Производственная база насчитывает более 9000 записей. Есть ли способ выполнить этот запрос на обновление 3 чуть быстрее, чем сейчас (~ 50 минут на компьютере разработчика).

INSERT INTO peoplesphones( phone, address ) 
SELECT DISTINCT `order`.phone, `order`.adress
FROM `order` 
GROUP BY `order`.phone;

Заполните таблицу народных телефонов уникальными телефонами

INSERT INTO peoplesaddresses( phone, address ) 
SELECT DISTINCT `order`.phone, `order`.adress
FROM `order` 
GROUP BY `order`.adress;

Заполните таблицу адресов народов уникальным адресом. Следующие три запроса очень медленные:

UPDATE peoplesaddresses, peoplesphones SET peoplesaddresses.people_id = peoplesphones.id WHERE peoplesaddresses.phone = peoplesphones.phone;

UPDATE peoplesaddresses, peoplesphones SET peoplesphones.people_id = peoplesaddresses.people_id WHERE peoplesaddresses.address = peoplesphones.address;

UPDATE `order`, `peoplesphones` SET `order`.people_id = `peoplesphones`.people_id where `order`.phone = `peoplesphones`.phone;

Наконец заполните таблицу сотрудников и очистите ненужные поля.

INSERT INTO peoples( id, name ) 
SELECT DISTINCT `order`.people_id, `order`.name
FROM `order` 
GROUP BY `order`.people_id;

ALTER TABLE `peoplesphones`
  DROP `address`;

ALTER TABLE `peoplesaddresses`
  DROP `phone`;

Итак, еще раз: как я могу сделать эти запросы UPDATE немного быстрее? THX.

UPD: Я забыл сказать: мне нужно сделать это сразу, просто для переноса телефонов и адресов в другие столы, так как один человек может иметь более одного телефона и может заказать пиццу не только в домой.

UPD2:

MySQL Variables UPD3:

Замените медленные обновления запросов на это (без с) ничего не получите.

UPDATE  peoplesaddresses
LEFT JOIN
        peoplesphones
ON      peoplesaddresses.phone = peoplesphones.phone
SET     peoplesaddresses.people_id = peoplesphones.id;

UPDATE  peoplesphones
LEFT JOIN
        `peoplesaddresses`
ON      `peoplesaddresses`.address = `peoplesphones`.address
SET     `peoplesphones`.people_id = `peoplesaddresses`.people_id;

UPDATE  `order`
LEFT JOIN
        `peoplesphones`
ON      `order`.phone = `peoplesphones`.phone
SET     `order`.people_id = `peoplesphones`.people_id;

UPD4 После добавления кода вверху (upd4) выполнение сценария занимает несколько секунд. Но при запросе ~ 6.5k он заканчивается текстом: «Системе не удается найти указанный диск».

Спасибо всем. Особенно для xQbert и Brent Baisley.

Ответы [ 2 ]

2 голосов
/ 18 декабря 2011

50 минут для 9000 записей - это немного смешно, событие без индексов. Вы также можете поместить 9000 записей в Excel и делать то, что вам нужно. Я думаю, что что-то еще происходит с вашей машиной разработчика. Возможно, у вас настроен mysql для использования очень мало памяти? Может быть, вы можете опубликовать результаты этого «запроса»:

show variables like "%size%";

Только сегодня утром я сделал вставку (игнорировать) / выделил две таблицы (одна в другую), каждая из которых содержит более 400 000 записей. 126 000 записей были вставлены во вторую таблицу, это заняло 2 минуты 13 секунд.

Я бы сказал, поместите индексы в любое из полей, к которым вы присоединяетесь или группируете, но это похоже на разовую работу. Я не думаю, что отсутствие индексов - ваша проблема.

2 голосов
/ 18 декабря 2011
  1. Все операции записи медленны в реляционных базах данных.Особенно индексы делают их медленными, так как они должны быть пересчитаны.
  2. Если вы используете WHERE в своих утверждениях, вы должны поместить индекс в указанные поля.
  3. GROUP BY всегда очень медленный, как и DISTINCT, так как им приходится делать много проверок, которые не масштабируются линейно.Всегда избегайте их.

Вы можете выбрать другой механизм базы данных для того, что вы делаете.9000 записей за 50 минут очень медленные.Поэкспериментируйте с несколькими различными движками, такими как MyISAM и InnoDB.Если вы часто используете временные таблицы, MEMORY действительно быстр для них.

Обновление : Кроме того, обновление нескольких таблиц в одном операторе, вероятно, не должно выполняться.

...