![]() |
Задавайте вопросы, мы ответим
Вы не зашли.
1. Когда что-то делаете, надо руководствоваться здравым смыслом. Написание
хранимого кода — не исключение.
Я решил, что, всё-таки лучше не выделываться и передавать ID, раз уж он там везде есть.
2. Почитайте про транзакции. Резервирование и отмена — это классические
примеры применения транзакций в жизни. Ну и для табличек InnoDB это уже
всё реализовано и хорошо работает (кроме SERIALIZABLE в 5.1, пока багу
не пофиксят).
Хм... Точно. Не думал я о транзакциях. Блин, зациклился я на этом "уникальном ID".
Спасибо.
Но, всё-таки, в данном случае, проблему вряд ли это решит.
В этой БД все таблицы MyISAM. Ведь не могу же я смешать MyISAM и InnoDB в рамках одной БД?
Или... Могу..?
Неактивен
Конечно можете, почему нет?
Неактивен
o.O Хм... Здорово...
А какие могут быть проблемы при таком "смешивании"?
И ещё:
1.) Если есть запросы select * from ..., InnoDB работает намного медленнее?
2.) Перенести базу куда-либо копированием уже будет нельзя?
3.) Везде используется MyISAM, но, например, при добавлении договоров, тоже требуются транзакции (вначале надо добавить группу водителей в отдельную таблицу) и т.д.. Количество записей в основных таблицах не очень большое: 15.5 тыс., 17.6, 27.1, 10.8, 18.5. Плюс имеются неиспользуемые таблицы, которые, в будущем могут пригодиться.
Имеет ли смысл переконвертировать всю БД в InnoDB?
И сколько примерно времени это может занять?
4.) В InnoDB есть проверка внешних ключей? Т.е., проверять наличие, например, клиента в процедуре добавления договора, при использовании InnoDB, не придётся?
5.) При работе с InnoDB, вообще, есть какие-то "особенности", по сравнению с MyISAM?
Неактивен
3) Важно не только количество строк, но и их длина, например. А также
производительность системы — дисков, памяти, процессоров. По опыту
небольшие таблички (~10к строк) альтерятся единицы секунд.
5) Например, Вы не можете в InnoDB завести табличку с полнотекстовым
индексом
Неактивен
vasya написал:
2) Да, простым копированием файлов не получиться. Но что мешает честно сделать дамп?
Ну, это же лишние сложности.
4) FAQ п4
FAQ прочитал. Спасибо. Хм... порадовал экспорт в Excel. Блин, и никакого COM!
5) Уточните, пожалуйста, что вы подразумеваете под "особенностями"?
Поведение, которое может быть неочевидным для человека, ранее не работавшего с данным движком.
paulus написал:
Например, Вы не можете в InnoDB завести табличку с полнотекстовым
индексом
Хм... Вот и особенность. К счастью, я его не использую.
Но некоторые поисковые движки ориентированные на MySQL, видимо, работать с InnoDB не будут...
А насчёт внешних ключей и транзакций, несколько вопросов для уточнения:
1.) При вставке в таблицу dogovor, с FK client(ID_CLIENT), возникнет ошибка, если клиент с таким ID не существует?
2.) При отключении клиента без завершения транзакции, она будет отменена?
3.) Могу ли я, при открытой транзакции, делать изменения, не входящие в неё?
Т.е., например, пользователь выбрал номер полиса. После этого, пришедший клиент подумал и решил добавить ещё одного водителя в договор.
Пользователь внёс водителя в БД.
В районе выключили электричество. Клиентское приложение отключилось от сервера.
Сервер должен разрезервировать договор, но оставить водителя, внесённого в базу.
Такое возможно сделать?
Ситуация вполне реальная (не с выключенным электричеством, конечно, а с точки зрения интерфейса).
Неактивен
Хм... Раньше возможно было переносить InnoDB простым копированием? А из-за чего нельзя сейчас?
Неактивен
Читаю потихоньку про InnoDB... Изменения, внесённые внутри незавершённой транзакции не будут видны "снаружи"?
Т.е., в любом случае, для такого резервирования вариант с транзакциями не подходит? Поскольку надо, чтобы другие пользователи видели, что бланк зарезервирован...
Неактивен
Делать действия независимо можете, конечно. Водителя надо добавлять в отдельном
соединении со своей транзакцией, ее закоммитить, а первую транзакцию трогать
при этом не нужно Относитесь к жизни проще, не надо создавать дополнительных
сложностей там, где всё просто.
Копировать бинарно можно, конечно, но надо соблюдать несколько правил:
- копировать надо все файлы: *.frm, *.ibd, ibdata*, желательно — iblog*
- копировать надо на остановленном сервере (иначе часть транзакций потеряете)
- копировать надо с сохранением каталогов, а не в одну кучу
- копировать надо также и настройки innodb в my.cnf
Или читаете в плохом месте, или еще не дочитали. Ключевые слова — «уровень
изоляции транзакции». Могут быть и видны снаружи.
Неактивен
Эх, жаль, что именованных транзакций нет... Видимо, придётся лишнее соединение делать. Наверное, способ единственный приемлемый. Спасибо.
Или читаете в плохом месте, или еще не дочитали. Ключевые слова — «уровень
изоляции транзакции». Могут быть и видны снаружи.
Не дочитал. Читаю.
Ещё пара вопросов:
1.) В некоторых таблицах, например, client, первичные ключи имеют следующий вид:
7600005050505111137187
7600005050505093327640
7600005050505092646937
И т.д.
Тип - VARCHAR(22).
Это не встроенная штука какая-то?
Или как тогда добавлять клиента в таблицу? Как создавать первичный ключ?
2.) Ведь в процедуру нельзя передать список никаким образом?
К примеру, в договоре прописывается список водителей.
Если использовать добавление/удаление с помощью отдельных процедур, то получается много лишних проблем. Может, возможно проще?
Отредактированно Артём Н. (09.04.2010 00:18:40)
Неактивен
Похоже на ИНН Я бы делал BIGINT — он занимает 8 байт, а не 22.
Заодно и бывает AUTO_INCREMENT.
Ну, можно в строке через запятую, но хорошо это не получится. А Вам
правда нужна процедура?
Неактивен
Похоже на ИНН smile Я бы делал BIGINT — он занимает 8 байт, а не 22.
Заодно и бывает AUTO_INCREMENT.
Не, ИНН хранится отдельным полем. Что сейчас с ними делать? Ведь в BIGINT Их не преобразовать же?
Ну, можно в строке через запятую, но хорошо это не получится. А Вам
правда нужна процедура?
Ну да. В процедуре проверяются права на добавление/изменение сущности.
А доступ на запись я, вообще, решил закрыть от греха подальше.
Хотя, конечно, добавлять договор может любой пользователь, а изменять только некоторые. Но, всё-равно, с правами - излишние сложности тогда получатся. Легче через процедуры.
Неактивен
Можете преобразовать, но бэкап перед этим сделайте всё-таки.
Сделайте тогда несколько процедур — процедура добавления договора,
процедура добавления водителя и процедура выдачи договора водителю.
Неактивен
но бэкап перед этим сделайте всё-таки.
Я сейчас на старой БД работаю. Когда преобразовывать буду, думаю, что оставлю старую, создам новую, старую в неё перегоню и пусть оба клиента отдельно работают.
Поскольку, я, как-бэ, сбоку. Предыдущий разработчик неиллюзорно прикалывался, видимо.
К примеру, некоторые ключи типа FLOAT.
Потом, были таблицы, типа bso_status. Ключа нет, в ней 5 уникальных записей, которые повторяются раз 60. Либо это какая-то фигня с СУБД, либо у меня руки кривые, но truncate на ней сдох. mysql клиент завис. DROP после этого тоже не работал. dbForge Studio вылетела с ошибкой. С грехом пополам, таблица всё-таки дропнулась... И всё в том же духе.
Можете преобразовать
Он говорит, что "out of range"...
mysql> alter table client modify id_client bigint;
ERROR 1264 (22003): Out of range value for column 'id_client' at row 1
Сделайте тогда несколько процедур — процедура добавления договора,
процедура добавления водителя и процедура выдачи договора водителю.
В том-то и дело... Договор не выдаётся водителю. Он выдаётся страхователю.
Водители вписываются в договор.
Т.е., водитель не может существовать без договора. Без договора существует клиент.
А таблица водителей примерно такая:
CREATE TABLE osago.drivers ( ID_DRIVER VARCHAR(22) NOT NULL, ID_CAR VARCHAR(22), ID_CLIENT VARCHAR(22), ID_DOGOVOR VARCHAR(22), DATE_INSERT DATE, DATE_UPDATE DATE, IMPORT_DATE DATETIME, PRIMARY KEY (ID_DRIVER), )
Т.е., передавать списком или делать процедуру, работающую в рамках той же самой транзакции, в которой добавляется договор.
Но, во-первых, что будет, если в рамках той же самой транзакции добавить клиента?
Во-вторых, в процедуре никак нельзя проверить работает ли процедура в рамках нужной транзакции...
Неактивен
Хм, действительно большие числа, не влезают
Тогда действительно или строка, или DECIMAL.
Сделайте тогда водителей во временной табличке отдельными процедурами,
а процедуру заведения договора сделайте копирующей данные из временной
таблички в реальную А вообще, я бы больше доверял программе, которую
Вы же сами и пишете — ограничить всё процедурами — дело хорошее... для
банков, например, а в реальной жизни можно и программам довериться
Неактивен
Хм, действительно большие числа, не влезают
Тогда действительно или строка, или DECIMAL.
Всё равно: "out of range"? Как же тогда ключи создавать на сервере?
Сделайте тогда водителей во временной табличке отдельными процедурами,
а процедуру заведения договора сделайте копирующей данные из временной
таблички в реальную
А как очищать временную таблицу, в случае сбоя клиента, например?
А вообще, я бы больше доверял программе, которую
Вы же сами и пишете — ограничить всё процедурами — дело хорошее... для
банков, например, а в реальной жизни можно и программам довериться
Ну банк или нет, разьве имеет значение? А за программами люди сидят.
Пусть даже это девочка-страховой агент (кстати, в большинстве там симпатичные блондинки ), разьве это имеет значение?
А как получить ID последней вставленной записи? Если не используется автоинкремент?
Отредактированно Артём Н. (16.04.2010 21:41:01)
Неактивен
Должно влезать, как создаете?
Очищать так же, как и любую другую таблицу — TRUNCATE.
Значение имеет. Если эта девушка, которая Вам нравится, не лезет в код —
она не сможет ничего испортить.
Если не используется автоинкремент, то Вы сами вставляете нужное значение,
поэтому получать Вам его не надо.
Неактивен
Должно влезать, как создаете?
mysql> alter table client modify id_client decimal;
ERROR 1264 (22003): Out of range value for column 'id_client' at row 1
Кстати, первая часть 76000... одинакова для всех (возможно, что это код региона).
Может, его как-то урезать возможно?
Или придумать аналогичную процедуру для создания первичного ключа?
Очищать так же, как и любую другую таблицу — TRUNCATE.
Ну, если клиент аварийно завершился, ведь записи останутся?
Значение имеет. Если эта девушка, которая Вам нравится, не лезет в код —
она не сможет ничего испортить.
Я привёл, как пример. Представьте себе абстрактную девушку в вакууме. Чисто теоретически, никто не мешает ей пользовать, вместо работы, фреймворк для создания эксплоитов или хотя-бы консольный клиент mysql.
Я, конечно, понимаю (на трезвую голову), что это невозможно, но тем не менее... o.O
Если не используется автоинкремент, то Вы сами вставляете нужное значение,
поэтому получать Вам его не надо.
Да, точно. Блин...
Положим я создаю ID на сервере с помощью процедуры. Вставляю запись (в транзакции). После чего, там же, пытаюсь получить ID... Мда, наверное, проще возвращать его в процедуре. Придумываю себе проблемы, которые потом решаю.
Неактивен
А last_insert_id() возвращает последний ID, который был вставлен? А если другой пользователь успеет вставить что-то, перед вызовом last_insert_id() текущим пользователем?
Отредактированно Артём Н. (17.04.2010 01:20:34)
Неактивен
Когда делаете DECIMAL — надо и размерность писать DECIMAL(23,0).
Если клиент завершится — то во временной табличке ничего не останется, т.к.
не останется таблички
Если Вас беспокоит доступ сферической девушки в вакууме с помощью клиента
mysql, то просто не говорите ей пароль. Если подберет — то подберет рутовый,
и никакие Ваши процедуры не помогут.
Живите проще, читайте документацию. Особенно про функциональность внутри
соединения — временные таблицы и insert_id — они выделяются на поток и ни
с кем никогда не конфликтуют
Неактивен
Мне нужно создать список водителей в "постоянной" таблице, из списка клиентов во временной таблице. Нужно создать ID к каждой записи, плюс, добавить ID договора и ТС.
Вначале думал, что для этого нужно использовать курсоры. Но почитал статейку:
http://habrahabr.ru/blogs/mysql/46333/
Кода для них много надо писать, а проблем ещё больше...
А возможно ли использовать такую конструкцию:
Select `bank`.* FROM `bank` LIMIT НОМЕР_НУЖНОЙ_НАМ_ЗАПИСИ,1
Чем она хуже?
Когда делаете DECIMAL — надо и размерность писать smile DECIMAL(23,0).
Сделал. Нормально всё переконвертировалось. Спасибо.
Если Вас беспокоит доступ сферической девушки в вакууме с помощью клиента
mysql, то просто не говорите ей пароль. Если подберет — то подберет рутовый,
и никакие Ваши процедуры не помогут.
Так "защита" с помощью процедур нужна не от сферической девушки в вакууме, у которой нет пароля, а от такой, у которой есть пароль.
Ведь, в данном случае, MySQL работает, как сервер.
Т.е., используется встроенный механизм полномочий и управления пользователями.
Каждый имеет свой аккаунт.
Живите проще, читайте документацию.
Хех, всю документацию не перечитаешь...
Неактивен
А временная таблица всегда создаётся в памяти? Независимо от такого какой параметр ENGINE я указываю? Или нет?
Неактивен
Ещё вопросы возникли (в документации, вроде ничего нету по данному, а проверять сейчас некогда):
set autocommit = false; start transaction; _действия_1_ start transaction; _действия_2_ if (error) then rollback; elseif (commit_allowed) then commit; end if; if (error) then rollback; else commit; end if;
1.) Что сделает первый rollback?
2.) Что сделает первый commit?
3.) Если первый commit не был выполнен, завершит ли обе транзакции второй commit?
4.) Если первый commit был выполнен, отменит ли второй rollback обе транзакции?
Отредактированно Артём Н. (24.04.2010 12:03:45)
Неактивен
Временная таблица создается не всегда в памяти — когда она перерастает
max_heap_table_size, она пишется на диск.
Транзакция бывает только одна. Следующий BEGIN автоматически применяет
предыдущую транзакцию. Если Вам нужны несколько транзакций — исполь-
зуйте точки сохранения.
Неактивен
Временная таблица создается не всегда в памяти — когда она перерастает
max_heap_table_size, она пишется на диск.
Это я понимаю. Но, если я создаю временную таблицу, с ENGINE равным, например, INNODB, она, всё-равно, будет создана в памяти?
А вариант выборки через LIMIT, типа такого:
Select `bank`.* FROM `bank` LIMIT НОМЕР_НУЖНОЙ_НАМ_ЗАПИСИ,1
будет аналогичен курсору, на временной таблице?
С транзакциями понятно. Транзакция мне нужна одна, но она может иметь несколько "входов". Т.е., в случае такого поведения, мне требуется как-то узнать была ли уже открыта транзакция.
Может, есть штатные средства (неохота заводить глобальную переменную)?
Следующий BEGIN автоматически применяет
А если BEGIN является началом процедуры/функции?
Например, функция такого вида:
CREATE
DEFINER = 'root'@'%'
FUNCTION GetCurUserFullname()
RETURNS TEXT
READS SQL DATA
SQL SECURITY INVOKER
COMMENT 'Получение полного имени текущего пользователя'
BEGIN
declare user_name CHAR(16);
declare user_host CHAR(60);
declare result TEXT;
call GetCurUser(user_name, user_host);
select concat_ws(' ', surname, name, pathronimyc) into result from user_data where
User = user_name and Host = user_host;
return result;
END;
select GetCurUserName();
тоже применит транзакцию? o.O
Неактивен