Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проблема с вызовом внутренней процедуры в MySQL 
:(
    Опции темы
boroda
Дата 27.9.2006, 11:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 2.12.2005
Где: Киев

Репутация: 1
Всего: 1



Добрый день.

Есть сторед процедура в MySQL

DROP PROCEDURE IF EXISTS `test`.`b_insert` $$
CREATE PROCEDURE `test`.`b_insert` (IN aName TEXT,
IN aCountry TEXT)
BEGIN
DECLARE country TEXT;
call b_getCountryID(@countryID,aCountry);
set country=@countryID;
insert into testTable(name, idCoutry) values(aName, country);
END $$
DELIMITER ; 

 Когда я ее вызываю процедуру b_insert из какого-либо клиента MySQL(MySQL Command Line Client, MySQL Query Browser), то внутрення процедура b_getCountryID возвращает нужное значение. Если же я вызываю b_insert из сервела то процедура b_getCountryID возвращает NULL. Где собака порылась? Или как можно решить данную проблему?

Заранее спасибо
PM MAIL   Вверх
3x3
Дата 28.9.2006, 15:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 261
Регистрация: 17.9.2006

Репутация: 5
Всего: 8



Цитата(boroda @ 27.9.2006,  11:30)
внутрення процедура b_getCountryID возвращает нужное значение. Если же я вызываю b_insert из сервела то процедура b_getCountryID возвращает NULL.

Видимо, если у вас b_getCountryID возвращает неправильное значение, то надо на неё и смотреть, а не на b_insert.

К тому же, вопрос, видимо в компетенции не этого, а вот этого форума..


--------------------
Зачем платить больше,
когда можно заплатить дважды?
PM   Вверх
boroda
Дата 28.9.2006, 18:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 2.12.2005
Где: Киев

Репутация: 1
Всего: 1



Цитата(boroda @ 27.9.2006,  11:30)
 Когда я ее вызываю процедуру b_insert из какого-либо клиента MySQL(MySQL Command Line Client, MySQL Query Browser), то внутрення процедура b_getCountryID возвращает нужное значение. Если же я вызываю b_insert из сервела то процедура b_getCountryID возвращает NULL. 


Как раз вопроса к MySQL у меня нет процедура b_getCountryID возвращает нужное значение (Поэтому считаю что мой вопрос в компетенции все-таки этого форума). Просто когда вызываю b_insert из java сервлета то b_getCountryID возвращает NULL.


Но всеравно спасибо


PM MAIL   Вверх
3x3
  Дата 29.9.2006, 00:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 261
Регистрация: 17.9.2006

Репутация: 5
Всего: 8



Не за что. 

Вот вам система из двух уравнений:

1. процедура b_getCountryID возвращает нужное значение.
2. из java сервлета b_getCountryID возвращает NULL.

Вывод из приведенной совокупности ваших утверждений только один: NULL - это нужное значение. 

Хотя что-то подсказывает мне, что вас понимать следует таким образом, что b_getCountryID не всегда возвращает правильное значение, так? А если это так, то и разбираться нужно с ней, а не с той процедурой, которая её использует, согласитесь. 







--------------------
Зачем платить больше,
когда можно заплатить дважды?
PM   Вверх
boroda
Дата 29.9.2006, 12:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 2.12.2005
Где: Киев

Репутация: 1
Всего: 1



smile) 
Ну вывод не правильный так как процедура b_getCountryID у меня в принципе не может вернуть NULL. Понимать следует именно так как я написал еще впервом сообщении. Т.е. при абсолютно одинакових  входящих параметрах если я пишу в MySQL Command Line Client к примеру call b_insert('Something','Russia'); Все работает отлично. В джава сервлете при вызове процедуры call b_insert('Something','Russia'). в таблицу testTable ничего не записывается по т.к. b_getCountryID возвращает NULL.

Вот код процедуры b_getCountryID
Код

DELIMITER $$

DROP PROCEDURE IF EXISTS `matco`.`b_getCountryID` $$
CREATE PROCEDURE `b_getCountryID`(OUT rows TEXT, IN aName TEXT)
BEGIN
 DECLARE done INT DEFAULT 0;
 DECLARE vIdCountry TEXT;
 DECLARE curIdCountry CURSOR FOR
   SELECT idCountry FROM country where name=aName;
 DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;

   OPEN curIdCountry;
   REPEAT
     FETCH curIdCountry INTO vIdCountry;
      IF NOT done THEN
       SET rows = vIdCountry;
      END IF;
   UNTIL done END REPEAT;
   CLOSE curIdCountry;

END $$

DELIMITER ;


а вот содержание таблицы country 
Код

+-----------+-------------+
| idCountry | Name        |
+-----------+-------------+
|         1 | Russia      |
|         2 | Switzerland |
+-----------+-------------+


P.S. Я конечно решил этот вопрос методом топора, т.е. в Java сервлете я изначально вызвал процедуру  b_getCountryID, потом b_insert и в нее я передал то что вернула мне b_getCountryID. Сейчас все работает, но при этом мне всеравно интересно в чем проблема?
PM MAIL   Вверх
3x3
Дата 29.9.2006, 16:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 261
Регистрация: 17.9.2006

Репутация: 5
Всего: 8



Я бы вам посоветовал рассмотреть вопрос о переходе с вызовов хранимых процедур на запросы вида:
Код

insert into testTable(name, idCoutry)  select 'lalala' /* it is your aName parameter */ ,idCountry from country where name='Russia' /* it is your aCountry */;

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

Что до NULL - он (а) всегда вставляется в testTable при вызове b_insert, (б) только при вызове b_insert из сервлета, но всегда, либо (в) произвольно?

Если Я бы на вашем месте для начала попытался избавиться от @-переменной.


--------------------
Зачем платить больше,
когда можно заплатить дважды?
PM   Вверх
Sun
Дата 29.9.2006, 16:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Account removed
***


Профиль
Группа: Экс. модератор
Сообщений: 1611
Регистрация: 14.8.2002

Репутация: 2
Всего: 48



Цитата(3x3 @  29.9.2006,  13:15 Найти цитируемый пост)
Мало того, что это будет переносимое решение, но оно так же обычно оказывается лучше по производительности.

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


--------------------
Account removed
PM MAIL   Вверх
3x3
Дата 29.9.2006, 16:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 261
Регистрация: 17.9.2006

Репутация: 5
Всего: 8



Кстати, а такая процедура не работает?

Код

CREATE PROCEDURE b_getCountryID(OUT rows TEXT, IN aName TEXT)
BEGIN
   SELECT idCountry INTO rows FROM country where name=aName;
END;


А такая вроде бы вообще должна возвращать значение подобно функции:
Код

CREATE PROCEDURE b_getCountryID(IN aName TEXT)
BEGIN
   SELECT idCountry FROM country where name=aName;
END;


Но лучше для этой конкретной цели использовать все-таки SQL-выражение..


--------------------
Зачем платить больше,
когда можно заплатить дважды?
PM   Вверх
3x3
Дата 29.9.2006, 17:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 261
Регистрация: 17.9.2006

Репутация: 5
Всего: 8



Цитата(Sun @ 29.9.2006,  16:35)
Цитата(3x3 @  29.9.2006,  13:15 Найти цитируемый пост)
Мало того, что это будет переносимое решение, но оно так же обычно оказывается лучше по производительности.

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

За MySQL не стану ручаться, но по аналогии с Oracle - запрос компилируется так же однократно, потом сидит в кеше. При этом, для данного типа запроса у него с большой вероятностью уже и данные в кеше готовые лежат, к справочнику-то часто обращаются, а вот процедуру всё равно придётся выполнить - оптимизатор не знает какова логика процедуры.
Плюс небольшие затратах на вызов процедуры в т.ч. инициализацию пакета, проверку привелегий и т.д., она ведь исполняется с правами своего владельца. 
Но главное, при использовании обращения к справочнику по странам в качестве подзапроса, оптимизатор запросов, работая с запросом ( в д.с. INSERT, но сложный SELECT был бы лучшим примером), будет его как нетрудно догадаться, оптимизировать - исходя из статистики таблиц к которым обращается запрос, наличия индексов, способа связывания и т.п. Он будет выбирать по каким индексам каких участвующих таблиц осуществлять внешние циклы, а по каким внутренние, да и по индексам ли вообще это делать. Заменяя подзапросы вызовами хранимых процедур вы лишите оптимизатор возможности выбора стратегии. 


--------------------
Зачем платить больше,
когда можно заплатить дважды?
PM   Вверх
batigoal
Дата 1.10.2006, 20:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нелетучий Мыш
****


Профиль
Группа: Участник Клуба
Сообщений: 6423
Регистрация: 28.12.2004
Где: Санктъ-Петербургъ

Репутация: 16
Всего: 151



Цитата(3x3 @  29.9.2006,  18:08 Найти цитируемый пост)
но по аналогии с Oracle - запрос компилируется так же однократно, потом сидит в кеше

Не совсем. Это было бы справедливо, если бы мы использовали PreparedStatement, и биндили его переменные. Если же мы будем втупую "склеивать" запрос, то он будет заново парситься, составляться план и т.д.


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли)
ЖоржЖЖ
PM WWW   Вверх
ALKS
Дата 1.10.2006, 21:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 354
Регистрация: 22.3.2006

Репутация: 6
Всего: 11



Угу. А в случае с MSSQL с увереностью берусь утверждать, что преренос кода в хранимые процедуры практически всегда лучшее с точки зрения производительности решение. и заметно лучшее.

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

п.с. простите искреен за офтоп. зацепило почему-то smile
PM   Вверх
3x3
Дата 1.10.2006, 22:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 261
Регистрация: 17.9.2006

Репутация: 5
Всего: 8



Цитата(batigoal @ 1.10.2006,  20:06)
Цитата(3x3 @  29.9.2006,  18:08 Найти цитируемый пост)
но по аналогии с Oracle - запрос компилируется так же однократно, потом сидит в кеше

Не совсем. Это было бы справедливо, если бы мы использовали PreparedStatement, и биндили его переменные. Если же мы будем втупую "склеивать" запрос, то он будет заново парситься, составляться план и т.д.

Не так. SQL-движок Oracle ничего не знает про JDBCшный PreparedStatement. Он получает select чего-то там через соединение, берет от него хеш и смотрит во внутренних структурах - а не завалялся ли там уже такой запрос и если нашел - берет адрес уже готовой структуры. Ну и с планом, вроде такая же фигня - во вью v$sql бывает можно встретить одинаковые запросы, с идентичными хешами, что меня заставляет думать, что они отличаются контекстом построения запроса (optimizer_env), но специально не интересовался, может и не по этому.

Биндинг переменных - естественно, по умолчанию. Это и безопаснее всегда, и в случае с Oracle, запросы должны быть идентичны, что бы их хеши сошлись.


--------------------
Зачем платить больше,
когда можно заплатить дважды?
PM   Вверх
3x3
Дата 1.10.2006, 23:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 261
Регистрация: 17.9.2006

Репутация: 5
Всего: 8



Цитата(ALKS @ 1.10.2006,  21:05)
Угу. А в случае с MSSQL с увереностью берусь утверждать, что преренос кода в хранимые процедуры практически всегда лучшее с точки зрения производительности решение. и заметно лучшее.


Никогда в жизни не поверю, что вызов процедуры может ускорить запрос.
Вот давайте возьмем табличку стран и табличку людей и попробуем вытащить имена всех австралийских мужчин:

Код

SELECT person.id, person.name FROM person, country, continent WHERE country.id=person.country_id AND person.sex='M' AND country.continent_id=continent.id AND continent.name='Australia';


Как должна отрабатывать база подобный запрос? Пойти перебирать людей сверяясь каждый раз с их страной и по ней с континентом, вызывая нужные функции?

Но ведь у нас 7 миллиардов людей сосредоточено в 200 странах и худо-бедно индексы существуют, и их селективность известна оптимизатору. По этому он найдет единственную страну на континенте Австралия и вытащит ветку индекса таблицы персон, содержащую указатели на персоны там живущие, и будет выбирать с диска блоки данных, содержащие только эти персоны, а не лопатить миллиарды записей персон.

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

И MySQL не может быть исключением. Он же тоже из каких-то соображений строит план запроса, использует те или иные индексы? Но как только вы начинаете пользоваться функциями - всё, оптимизация идёт лесом. 


Цитата

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

Но нет смысла городить сложности на пустом месте. В специальных случаях, когда не работает общее решение - никто не мешает его оговорить особо -  перерекрыть общий случай, работающий везде своими настройками, подогнанными под частный случай. Так и надо разрабатывать софт, ведь дело не только в переносимости между RDBMS, дело в переносимости продукта между разными клиентами, сидящими под одной и той же версией RDBMS. У всех разные "обстоятельства" в базе и продукт должен быть готов быть немного подкручен под конкретный случай. Под одним заказчиком сидеть прикажете? Так он вас же и купит в итоге smile


Цитата

п.с. простите искреен за офтоп. зацепило почему-то smile

Теперь оправдываться поздно. Посмотри на это небо, эти звёзды..


--------------------
Зачем платить больше,
когда можно заплатить дважды?
PM   Вверх
batigoal
Дата 2.10.2006, 08:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нелетучий Мыш
****


Профиль
Группа: Участник Клуба
Сообщений: 6423
Регистрация: 28.12.2004
Где: Санктъ-Петербургъ

Репутация: 16
Всего: 151



Цитата(3x3 @  1.10.2006,  23:54 Найти цитируемый пост)
Не так.

Ээээ... А в чем же тут противоречие с моими словами?


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли)
ЖоржЖЖ
PM WWW   Вверх
3x3
Дата 2.10.2006, 11:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 261
Регистрация: 17.9.2006

Репутация: 5
Всего: 8



Цитата(batigoal @ 2.10.2006,  08:36)
Цитата(3x3 @  1.10.2006,  23:54 Найти цитируемый пост)
Не так.

Ээээ... А в чем же тут противоречие с моими словами?

1. PreparedStatement ни при чем
2. Случай с параметрами, вписанными внутрь запроса просто не рассматривается

А в остальном - всё так, конечно smile


--------------------
Зачем платить больше,
когда можно заплатить дважды?
PM   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема »


 




[ Время генерации скрипта: 0.0578 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.