Хранимые процедуры
От: alexdev Россия http://alexdev-ru.livejournal.com
Дата: 09.02.10 18:54
Оценка:
Доброго времени суток, коллеги!

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

1. Есть хранимка (>500 строк) текст которой, это один большой Case. Не лучше ли было вынести каждую ветку кейса, в отдельную хранимку? Думаю, это прибавит производительности.

2. Есть хранимки, которые принимают > 10 параметров, и в коде часто параметрам передается null.. Не проще было бы опять несколько хранимок написать? Как это отражается на безопасности и производительности?

Ну, про всякого рода
"SELECT * FROM table WHERE field2="+param2+" .... "
, я уж вообще молчу.. Ладно хоть продукт предназначен для внутреннего использования, а не для продаж..

Есть какие-нибудь доки о том как правильно писать хранимки? Что можно почитать, кроме собственно документации к БД?

P.S. А то невольно начинает возникать мысль "Господи, куда я попал?! "
... << RSDN@Home 1.2.0 alpha 4 rev. 1410>>
Re: Хранимые процедуры
От: MozgC США http://nightcoder.livejournal.com
Дата: 09.02.10 19:06
Оценка:
Здравствуйте, alexdev, Вы писали:

A>1. Есть хранимка (>500 строк) текст которой, это один большой Case. Не лучше ли было вынести каждую ветку кейса, в отдельную хранимку? Думаю, это прибавит производительности.

Производительности прибавит навряд ли, а вот логическое структурирование (декомпозиция) будет лучше. Поддерживать проще будет. Но чтобы точно ответить надо смотреть код хранимки.

A>2. Есть хранимки, которые принимают > 10 параметров, и в коде часто параметрам передается null.. Не проще было бы опять несколько хранимок написать? Как это отражается на безопасности и производительности?

Нужно смотреть конкретный случай. Очень возможно что не проще. Например если ХП делает выборку и если параметр не null, то он участвует в фильтрации, а если не null — то не участвует, т.е. что-то типа
... AND (SupplierID_ IS NULL OR SupplierID = SupplierID_)
то я бы предпочел как раз такую ХП, а не десять с разными вариациями where-фильтра вместо неё.
Re[2]: Хранимые процедуры
От: alexdev Россия http://alexdev-ru.livejournal.com
Дата: 09.02.10 19:16
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Здравствуйте, alexdev, Вы писали:


A>>1. Есть хранимка (>500 строк) текст которой, это один большой Case. Не лучше ли было вынести каждую ветку кейса, в отдельную хранимку? Думаю, это прибавит производительности.

MC>Производительности прибавит навряд ли, а вот логическое структурирование (декомпозиция) будет лучше. Поддерживать проще будет. Но чтобы точно ответить надо смотреть код хранимки.

код привести не могу, но постараюсь изложить суть
допустим эта процедура с 5 параметрами, код примерно следующий

BEGIN
CASE param1
WHERE 'Get1' THEN ... // 100-200 строк
WHERE 'Get2' THEN ... // 100-200 строк
WHERE 'Get3' THEN ... // 100-200 строк
END CASE;
END;

Я не знаю как хранимка выполняется на сервере, но могу предположить, что примерно также, как и исполняемые файлы. т.е. скомпилированная хранимка, проецируется в память (или она всегда там висит? ) Ну и собственно выполняется. Если она каждый раз проецируется в память, то думаю, что резоннее разбить на несколько..

A>>2. Есть хранимки, которые принимают > 10 параметров, и в коде часто параметрам передается null.. Не проще было бы опять несколько хранимок написать? Как это отражается на безопасности и производительности?

MC>Нужно смотреть конкретный случай. Очень возможно что не проще. Например если ХП делает выборку и если параметр не null, то он участвует в фильтрации, а если не null — то не участвует, т.е. что-то типа
MC>
... AND (SupplierID_ IS NULL OR SupplierID = SupplierID_)
то я бы предпочел как раз такую ХП, а не десять с разными вариациями where-фильтра вместо неё.

точно сказать не могу, но where-фильтров в коде достаточно. Ладно еще когда 10 входных параметров, но когда входных параметров >= 30 ...
... << RSDN@Home 1.2.0 alpha 4 rev. 1436>>
Re[3]: Хранимые процедуры
От: MozgC США http://nightcoder.livejournal.com
Дата: 09.02.10 19:38
Оценка: 1 (1) :)
Здравствуйте, alexdev, Вы писали:

A>допустим эта процедура с 5 параметрами, код примерно следующий


A>BEGIN

A>CASE param1
A> WHERE 'Get1' THEN ... // 100-200 строк
A> WHERE 'Get2' THEN ... // 100-200 строк
A> WHERE 'Get3' THEN ... // 100-200 строк
A>END CASE;
A>END;

Разбивайте. Ну и что могу сказать, крепитесь
Re[4]: Хранимые процедуры
От: alexdev Россия http://alexdev-ru.livejournal.com
Дата: 09.02.10 19:44
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Разбивайте. Ну и что могу сказать, крепитесь


Спасибо, постараюсь
... << RSDN@Home 1.2.0 alpha 4 rev. 1436>>
Re: Хранимые процедуры
От: Nonmanual Worker  
Дата: 10.02.10 03:34
Оценка:
Здравствуйте, alexdev, Вы писали:

A>У меня следующая ситуация. В базах данных я не специалист, но так случилось, что сейчас работаю над проектом с БД. Проект большой и не мой, мне поручают его поддерживать. Вобщем, заметил, на мой взгляд, серьезные ошибки в хранимых процедурах:

БД на абстрактной СУБД или на конкретной? Работа с хранимками на разных серверах имеет свои особенности.

A>1. Есть хранимка (>500 строк) текст которой, это один большой Case. Не лучше ли было вынести каждую ветку кейса, в отдельную хранимку? Думаю, это прибавит производительности.

Производительность врядли.
Строк конечно многовато, но смотря что она делает, если этот case использован в стиле индийского программирования — то это очень плохо для программиста.

A>2. Есть хранимки, которые принимают > 10 параметров, и в коде часто параметрам передается null.. Не проще было бы опять несколько хранимок написать? Как это отражается на безопасности и производительности?

Страшного не вижу. Может даже часть зарезервировны.

A>Ну, про всякого рода
"SELECT * FROM table WHERE field2="+param2+" .... "
, я уж вообще молчу.. Ладно хоть продукт предназначен для внутреннего использования, а не для продаж..

Не очень хорошо. Хотя это смотря какой сервак...

A>Есть какие-нибудь доки о том как правильно писать хранимки? Что можно почитать, кроме собственно документации к БД?

гугл
Re[2]: Хранимые процедуры
От: alexdev Россия http://alexdev-ru.livejournal.com
Дата: 10.02.10 05:45
Оценка:
Здравствуйте, Nonmanual Worker, Вы писали:

NW>БД на абстрактной СУБД или на конкретной? Работа с хранимками на разных серверах имеет свои особенности.


MySQL
... << RSDN@Home 1.2.0 alpha 4 rev. 1436>>
Re: Хранимые процедуры
От: Sshur Россия http://shurygin-sergey.livejournal.com
Дата: 10.02.10 07:35
Оценка:
Здравствуйте, alexdev, Вы писали:


A>1. Есть хранимка (>500 строк) текст которой, это один большой Case. Не лучше ли было вынести каждую ветку кейса, в отдельную хранимку? Думаю, это прибавит производительности.


Производительность вряд ли сильно возрастет, а вот читабельность и поддерживаемость возрастет в разы. Это если правильно разбить на мелкие. Сколько там процедур и что за сервер? на MSSQL при правильном именовании процедур можно поддерживать базу с несколькими тысячами хранимок, тут уже обсуждалось неоднократно.


A>2. Есть хранимки, которые принимают > 10 параметров, и в коде часто параметрам передается null.. Не проще было бы опять несколько хранимок написать? Как это отражается на безопасности и производительности?


На безопасность и производительность сам факт того, что параметру Null передается, никак не влияет. Но вот если внутри не все варианты параметров проверяются — тогда ой.


A>Ну, про всякого рода
"SELECT * FROM table WHERE field2="+param2+" .... "
, я уж вообще молчу.. Ладно хоть продукт предназначен для внутреннего использования, а не для продаж..


Drop table students, ага


A>Есть какие-нибудь доки о том как правильно писать хранимки? Что можно почитать, кроме собственно документации к БД?

A>P.S. А то невольно начинает возникать мысль "Господи, куда я попал?! "

Надо читать что-то по общей культуре программирования, как-то разбивания кода на мелкие логически связанные действия, недопустимости спагетти итд.
Шурыгин Сергей

"Не следует преумножать сущности сверх необходимости" (с) Оккам
Re: Хранимые процедуры
От: Plague Россия  
Дата: 10.02.10 15:58
Оценка: 3 (2)
Здравствуйте, alexdev, Вы писали:

A>Доброго времени суток, коллеги!


A>У меня следующая ситуация. В базах данных я не специалист, но так случилось, что сейчас работаю над проектом с БД. Проект большой и не мой, мне поручают его поддерживать. Вобщем, заметил, на мой взгляд, серьезные ошибки в хранимых процедурах:


A>1. Есть хранимка (>500 строк) текст которой, это один большой Case. Не лучше ли было вынести каждую ветку кейса, в отдельную хранимку? Думаю, это прибавит производительности.

MySQL поддерживает IF/THEN и переменные, что очень часто гораздо «чище» выглядит, чем множество CASE. Не обязательно все писать одним монструозным запросом! Главное — чтоб код был простым.

A>2. Есть хранимки, которые принимают > 10 параметров, и в коде часто параметрам передается null.. Не проще было бы опять несколько хранимок написать? Как это отражается на безопасности и производительности?

> 10 — это нормально... но в целом, надо призадуматься, а не передается ли лишних данных, например которые можно было бы выудить опосредованно, например передавать не (КЛЮЧДОКУМЕНТА,ДАТА,НОМЕР,СОТРУДНИК), а только КЛЮЧДОКУМЕНТА.

A>Ну, про всякого рода
"SELECT * FROM table WHERE field2="+param2+" .... "
, я уж вообще молчу.. Ладно хоть продукт предназначен для внутреннего использования, а не для продаж..

Вроде, с «PARAMETER BINDING»(не знаю как по-русски) у MySQL проблемы, хотя могу ошибаться, вроде как библиотеки есть, но далеко не идеальны. У Оракла все замечательно они двух зайцев убивают этим — исключает «SQL Injection» и позволяет оптимизатору кэшировать запросы. И это еще в книге Тома Кайта сказано, что оптимизатор понимает запросы с разными параметрами но использующие PB как одинаковые запросы, а не использующие считаются разными. Так в одной «программе» видел как излишне наворачивались запросы (типа, получения имени текущего табличного пространства, проверки модуля и т.п.), при том некоторые параметры именно «вшивались» в запрос, в результате запрос отрабатывал 15сек, когда делался «PARAMETER BINDING» запрос отрабатывал 0.2сек. Кстати, это одна из причин, по которой останавливать базу Оракла не очень хорошо — вроде как кэши сбрасываются и он заново начинает статистику по запросам собирать.

A>Есть какие-нибудь доки о том как правильно писать хранимки? Что можно почитать, кроме собственно документации к БД?

Тут надо подходить здраво, на надо все переносить на хранимки. Надо делать их как можно проще (как, в прочем, не только в SQL), тогда легче будет их поддерживать, а в SQL не все просто бывает с поддержкой, когда процедур свыше 2к, а еще есть проверка прав доступа и все такое.

Добавлю, что с хранимками для MySQL тут не недавно «встрял». На одном известном популярном хостере они просто НЕ РАБОТАЮТ. даже те, что содержат только "select 1 from dual;" Оказалось надо запустить какую-то консольную утилиту MySQL для исправления безобразия. Не говоря уже о встреченных багах. Очевидно, что мало кто пользуется процедурами в реальности и именно поэтому "SQL Injection" так распространен.

A>P.S. А то невольно начинает возникать мысль "Господи, куда я попал?! "

Это больше зависит от уровня программиста и уровня кода.
Re[2]: Хранимые процедуры
От: alexdev Россия http://alexdev-ru.livejournal.com
Дата: 10.02.10 17:31
Оценка:
Здравствуйте, Plague, Вы писали:

P>MySQL поддерживает IF/THEN и переменные, что очень часто гораздо «чище» выглядит, чем множество CASE. Не обязательно все писать одним монструозным запросом! Главное — чтоб код был простым.


Тем не менее — выглядит устрашающе

P>Вроде, с «PARAMETER BINDING»(не знаю как по-русски) у MySQL проблемы....


Спасибо, обязательно почитаю!

P>Тут надо подходить здраво, на надо все переносить на хранимки. Надо делать их как можно проще (как, в прочем, не только в SQL), тогда легче будет их поддерживать, а в SQL не все просто бывает с поддержкой, когда процедур свыше 2к, а еще есть проверка прав доступа и все такое.


Заметил одну ХП из ~5000 строк. Предложил разбить на несколько, на что, получил ответ: "А зачем?". Отвечаю, что поддерживать легче и вообще, есть ли уверенность, что ~5000 строк написаны оптимальным для MySQL образом?..
Вообщем

P>Добавлю, что с хранимками для MySQL тут не недавно «встрял». На одном известном популярном хостере они просто НЕ РАБОТАЮТ. даже те, что содержат только "select 1 from dual;" Оказалось надо запустить какую-то консольную утилиту MySQL для исправления безобразия. Не говоря уже о встреченных багах. Очевидно, что мало кто пользуется процедурами в реальности и именно поэтому "SQL Injection" так распространен.


Я считаю, что исправить в коде уязвимость такого рода, чем менять ХП в базе (тут уже надо, какбэ сообща )

A>>P.S. А то невольно начинает возникать мысль "Господи, куда я попал?! "

P>Это больше зависит от уровня программиста и уровня кода.

Удивительно то, что я не считаю себя программистом высокого уровня, да и годков мне поменьше чем тем, кто писал все это...
... << RSDN@Home 1.2.0 alpha 4 rev. 1436>>
Re[3]: Хранимые процедуры
От: Nonmanual Worker  
Дата: 11.02.10 03:34
Оценка:
Здравствуйте, alexdev, Вы писали:

A>MySQL

Это несколько меняет дело.
В дополнение к посту от Plague добавлю.
Хранимки в MySQL появились уже довольно давно, но все равно остаются весьма глючными, к тому-же в них есть существенное кол-во ограничений.
Почитайте соответствующие вашей версии доки (http://dev.mysql.com/doc/refman/5.1/en/stored-program-restrictions.html) перед любым рефакторингом.
Re[3]: Хранимые процедуры
От: Plague Россия  
Дата: 11.02.10 07:47
Оценка: 2 (1)
Здравствуйте, alexdev, Вы писали:

P>>Добавлю, что с хранимками для MySQL тут не недавно «встрял». На одном известном популярном хостере они просто НЕ РАБОТАЮТ. даже те, что содержат только "select 1 from dual;" Оказалось надо запустить какую-то консольную утилиту MySQL для исправления безобразия. Не говоря уже о встреченных багах. Очевидно, что мало кто пользуется процедурами в реальности и именно поэтому "SQL Injection" так распространен.


A>Я считаю, что исправить в коде уязвимость такого рода, чем менять ХП в базе (тут уже надо, какбэ сообща )


Тут именно вопрос в том что легче: дописывать везде код для недопущения уязвимости (но в реальности, все допускают ошибки и где-то проверку забудете) или искоренить SQL Injection как класс используя Parameter binding и хорошо настроенный ограниченный доступ к базе? По правильному можно ограничить доступ к таблицам — запретить писать и читать из таблиц, а только из разрешенных вьюх, при том сами вьюхи будут отдавать данные только авторизированному пользователю. Соответственно разграничить и доступ к процедурам.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.