Здесь курят мануал.

Добро пожаловать на Пыху!

Логин:
Пароль:
 

Нет прописки? Зарегистрируйся!

Новости

Мы в твиттере!
Мы вконтакте!
Мы на яндексе!

Краснодарское время: 24 Май, 2012, 08:10:16

Страниц: [1] 2
Печать
Автор Тема: Задачка.  (Прочитано 1798 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Batler    ↓ 
15 Август, 2009, 01:29:49
НЕ ХУЕТА! ХУЕТА!

Карма: 4
Сообщений: 142
Сила слова: 2.82

Есть таблица `hotels`. Структура следующая:
SQL

id INT AUTO INCREMENT PRIMARY KEY,
name TINYTEXT CHARACTER SET utf8,
region TINYTEXT CHARACTER SET utf8,
type TINYTEXT CHARACTER SET utf8
 

Мне нужно вставлять в нее строки, причем так, чтобы комбинация name|region|type была уникальная. Как лучше это сделать?
У меня есть идея с использованием UNIQUE KEY comb (name(100), region(50), type(20)) и тогда писать в INSERT'e игнор на повторяющиеся строки.
Только я не уверен, что все это будет работать.
Записан
md5    ↓ 
15 Август, 2009, 01:31:20 , спустя 1 минуту 31 секунду
НЕ ХУЕТА! ХУЕТА!

выезд, апартаменты, массаж, стриптиз, подружки, дорого
Группа: в ухо

Карма: не нужна
Сообщений: 10494
Сила слова: 1.19

а почему не уверен?
не уверен — не играй!
Записан

8: Undefined variable: str
Файл: /home/pyha/pyha.ru/forum/bbcode/Xbb/Tags/Man.php
Строка: 18
adw0rd: мудень блять, я уже фиксить стал эту фигню :)
md5: вуахахахаха
Batler    ↓ 
15 Август, 2009, 01:33:28 , спустя 2 минуты 8 секунд
НЕ ХУЕТА! ХУЕТА!

Карма: 4
Сообщений: 142
Сила слова: 2.82

Столбец name может содержать более 100 символов, значит в индекс войдет не все
ну и другие подводные камни этого варианта решения
Записан
Batler    ↓ 
15 Август, 2009, 07:08:35 , спустя 5 часов 35 минут 7 секунд
НЕ ХУЕТА! ХУЕТА!

Карма: 4
Сообщений: 142
Сила слова: 2.82

Ок. С индексом получилось. Как теперь его заюзать в селект запросе.
Критерий такой WHERE ROW(name,region,type) IN ( (a,b,c), (d,e,f), (g,h,i) ).
Экслпеин говорит, юзать его не буду, даже если явно прописать USE KEY в SELECT
Записан
phpdude    ↓ 
15 Август, 2009, 07:12:49 , спустя 4 минуты 14 секунд
НЕ ХУЕТА! ХУЕТА!

я - ЭМО
Группа: в ухо

Карма: 344
Сообщений: 20782
Сила слова: 1.66

пошли всю структуру страницы + запрос который хочешь выполнять
Записан

забанен. могу забанить других, пишите в личку
BEER. Helping ugly people have sex since 1862.
Batler    ↓ 
15 Август, 2009, 11:36:48 , спустя 4 часа 23 минуты 59 секунд
НЕ ХУЕТА! ХУЕТА!

Карма: 4
Сообщений: 142
Сила слова: 2.82

Страница - но принт. Скрипт будет в консоли крутиться. Вобщем не важно, вот код
PHP

$hotelinfo;  # список, в котором в формате НАЗВАНИЕ ОТЕЛЯ|РЕГИОН|ТИП хранятся данные. строки могут повторяться, а в бд такого не надо.
$unq = array_unique($hotelinfo);  #Рассматриваем неповторяющиеся записи.
/*
*Тут можно пойти 2мя путями. Сделать запрос вида SELECT name, region, type FROM `hotels` WHERE ROW(name, region, type) IN...
* Или задать индекс по столбцам name, region, type и объявить его уникальным. Тогда повторов в таблице не будет.
*/

//Коннект к БД
$db = DB::getDB();
$select = 'SELECT name, region, type FROM `hotels` WHERE ROW(name, region, type) IN (';
foreach ($unq as $k => &$v) {
   $m = explode('|',$v);
   $select .= $db->prepare('($0,$1,$2), ', array($m[0],$m[1],$m[2]));
}
$select = substr($select, 0, sizeof($select) - 2) . ')';
$res = $db->query($select, null, 'assoc');
//Теперь в $res лежат отели, которые уже есть в базе. Их вставлять не надо...
 
//Далее идет инсерт в таблицу исключая отели, которые уже есть. Тут не очень интересный код.
 
//Затем вставленные отели снова выбираются из таблицы, чтобы узнать их ID, а потом этот ID записывается в другую таблицу.
 

Структура таблицы:
SQL
id INT AUTO INCREMENT PRIMARY KEY,
name TINYTEXT CHARACTER SET utf8,
region TINYTEXT CHARACTER SET utf8,
type TINYTEXT CHARACTER SET utf8

Пробовал так:
 
SQL
id INT AUTO INCREMENT PRIMARY KEY,
name VARCHAR(100) CHARACTER SET utf8,
region VARCHAR(100) CHARACTER SET utf8,
type VARCHAR(20) CHARACTER SET utf8,
UNIQUE KEY nrt (name(100), region(100), type(20)))

Тогда селект, который я написал выше вообще больше не нужен, но инсерт начинает тормозить.
« Последнее редактирование: 15 Август, 2009, 11:36:18 от Batler » Записан
phpdude    ↓ 
15 Август, 2009, 11:38:58 , спустя 2 минуты 10 секунд
НЕ ХУЕТА! ХУЕТА!

я - ЭМО
Группа: в ухо

Карма: 344
Сообщений: д-о-х-у-я!
Сила слова: 1.66

но инсерт начинает тормозить.
 
таблички myisam видимо юзаешь. + сколько записей в таблицах?
Записан

забанен. могу забанить других, пишите в личку
BEER. Helping ugly people have sex since 1862.
Batler    ↓ 
15 Август, 2009, 11:49:18 , спустя 10 минут 20 секунд
НЕ ХУЕТА! ХУЕТА!

Карма: 4
Сообщений: 142
Сила слова: 2.82

вообще толстеют очень быстро =)
пока под 4,5к в одной и около 250к в связанной с ней =)
Спустя 59 секунд добавил
4,5k - hotels
Записан
phpdude    ↓ 
15 Август, 2009, 11:54:18 , спустя 5 минут
НЕ ХУЕТА! ХУЕТА!

я - ЭМО
Группа: в ухо

Карма: 344
Сообщений: 20782
Сила слова: 1.66

попробуй на иннодб смени таблицы, может отпадут тормоза)
Записан

забанен. могу забанить других, пишите в личку
BEER. Helping ugly people have sex since 1862.
Batler    ↓ 
16 Август, 2009, 12:15:08 , спустя 20 минут 50 секунд
НЕ ХУЕТА! ХУЕТА!

Карма: 4
Сообщений: 142
Сила слова: 2.82

Это можно... Еще можно вместо инсерта из файлика загрузку делать...
Индекс очень сильно тормозит на вставке, но самое стремное, он потом в селекте не используется.
Ладно, пробовать буду завтра... посмотрим че выйдет...
Записан
ghost    ↓ 
21 Август, 2009, 01:03:48 , спустя 5 дней 48 минут 40 секунд
НЕ ХУЕТА! ХУЕТА!

без вариантов
Группа: в ухо

Карма: 29
Сообщений: 876
Сила слова: 3.31

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

Если ты уже два часа споришь с идиотом - скорее всего он делает тоже самое...
Batler    ↓ 
21 Август, 2009, 12:19:06 , спустя 11 часов 15 минут 18 секунд
НЕ ХУЕТА! ХУЕТА!

Карма: 4
Сообщений: 142
Сила слова: 2.82

Угу, звездность и все такое (5+ HV-1 и т.п.). А названия отелей одинаковые, т.к. это политика управления брендом.
Да и как триггер поможет в проверке уникальности? Можно конечно что-то там придумать, но я пока остановился на варианте SELECT -> поиск совпадений->INSERT->SELECT для вставки в другую таблицу и т.п.
« Последнее редактирование: 21 Август, 2009, 12:19:06 от Batler » Записан
AndryG    ↓ 
21 Август, 2009, 03:58:21 , спустя 3 часа 39 минут 15 секунд
НЕ ХУЕТА! ХУЕТА!
Группа: Адекваты

Карма: 1
Сообщений: 233
Сила слова: 0.43

Не знаю, как mySQL (поддерживает ли он "insert into () select")
Может такой вариант сойдет?
SQL
INSERT INTO hotels (name,region,type_)
SELECT :name, :region, :type
FROM rdb$database -- Это таблица с одной строкой. Для mySQL, кажись, можно просто убрать предложение FROM
WHERE NOT EXISTS(SELECT * FROM hotels WHERE name = :name AND region = :region AND type_ = :type)

Если использовать mysqli, то предварительная подготовка запроса в самом начале работы скрипта должна Вам помочь с быстродействием.
Спустя 1 минуту 34 секунды добавил
type_ c подчеркивание в конце, ибо "type" у меня - служебное слово
Записан
Batler    ↓ 
21 Август, 2009, 04:50:36 , спустя 52 минуты 15 секунд
НЕ ХУЕТА! ХУЕТА!

Карма: 4
Сообщений: 142
Сила слова: 2.82

Prepared statement выполняются медленее в MySQL. Пруфлинк давал в другой ветке (см обсуждение класса для работы с БД).
И я не понял немного логики этого запроса. Вставить в таблицу hotels значения, которые вернет оператор SELECT (а он вернет параметры которые мы проверяем, при условии, что вложенный запрос ничего не вернет). Если я правильно понял запрос, то тут есть проблемы:
1) У нас массив отелей, значит запросов будет множество (пусть даже заранее подготовленных, но тем не менее их будет множество).
2) Подзапрос в запросе. Это тоже не добавит к скорости.
3) Я тоже не уверен, что MySQL держит селект в инсерте. В моей литературе сказано, что не держит, но там версия древняя.
 
UPD: http://www.mysql.ru/docs/man/INSERT_SELECT.html Есть такая возможность, но там сказано, что нельзя использовать
ту  же таблицу, куда производится вставка.
Записан
AndryG    ↓ 
21 Август, 2009, 09:03:05 , спустя 4 часа 12 минут 29 секунд
НЕ ХУЕТА! ХУЕТА!
Группа: Адекваты

Карма: 1
Сообщений: 233
Сила слова: 0.43

Prepared statement
Из той ветки я понял, что подготовленный запрос выполняется медленнее, если он единственный.
А если сравнить выполнение 1000 раз запроса обычного и 1000 раз запроса предварительно подготовленного (1 подготовка и 1000 выполнений)
 
Если и на многократном исполнении подготовленный запрос проигрывает, то я вообще в шоке от этой СУБД :)
  (Но это уже вариации ПО - не будем спорить - делайте, как быстрее)
 
Подзапрос в запросе.
 Подзапрос там "легкий" (exists) - СУБД не будет считать сикоко там записей нашлось, ни, тем паче, выдавать их клиенту.
 Да и наш подзапрос ложится в Ваш индекс - вообще мелочи
 
insert into select Поддерживает? Замечательно! "нельзя использовать ту же таблицу, куда производится вставка." -- а мы так и не делаем.
 
Посмотрите на свой код.
 1. Формирование списка IN в foreach - это страшно. Вот где точно тормозить должно. Если IN и используете - стремитесь к его минимальному наполнению.
 2. Сперва Вы вытаскиваете (про страшность метода сказано в п.1)  на клиента список существующих отелей.
      Для этого заставляете СУБД просмотреть ВЕСЬ ваш список (в IN его запихнув)
 3. Потом в "неинтересном коде" Вы фильтруете "вставлять/не всталять" - опять просматриваете ВЕСЬ список.
 4. Потом Вы еще раз выбираете вставленные отели ... я так понимаю, что это такой же страшный IN  ПОЧТИ ВЕСЬ список - часть отсеялась в п.3
 
Частенько встречается слово ВЕСЬ. И данные в/из СУБД гоняются многократно.
 
Пункт 4 убирается просто. ID записи нужно вставлять вместе с данными ... другими словами его надоть узнать ДО вставки. Для этого используются последовательности (SEQUENCE) или их имитация (в гугле полно по этому поводу http://sqlinfo.ru/forum/viewtopic.php?id=813).
В данном случае можно по другом:
 Вставили одну запись;
 LAST_INSERT_ID() -- узнали ID и куда надо его и ставим; (используя мой запрос .. нужно контролировать, изменилось ли значение, ибо там вставка происходит не всегда)
 
 
« Последнее редактирование: 21 Август, 2009, 09:03:05 от AndryG » Записан
Страниц: [1] 2
Печать
 

Перейти в: