Как узнать, что OracleCommand уже находится в состоянии Prepared?

Имею WinForm приложение и БД Oracle, к которой нужно корректно подключиться.

"Корректно" это вот так: если в момент выдачи очередного запроса кто-то выдернет сетевой шнур сервера из розетки, программа у клиента не виснет, а начинает тестировать связь с сервером (в цикле ping, затем tnsping, затем select * from dual) и после того как сервер снова оживёт, автоматически обратно коннектится и продолжает работу. Для этих целей написан код внизу, который выполняется в начале каждого обращения к БД из модулей программы.

 private static Oracle.ManagedDataAccess.Client.OracleConnection oconn;
 private static Oracle.ManagedDataAccess.Client.OracleCommand ocmd;
...
            do try {
                if (oconn.State == ConnectionState.Closed) oconn.Open();
                if ((SQL.Length > 0) && (ocmd.CommandText != SQL)) ocmd.CommandText = SQL;   
                // вставить проверку: Prepared?, 
                // повторно Prepare() не выдавать, чтобы не валить сервер разборами запросов.
                ocmd.Prepare(); 
            } catch (Exception e) { 
                if (!uConnectTest.ConnectTest(null, e.Message)) { // модальный вызов модуля тестирования
                    Cursor.Current = Cursors.Default;
                    return false; 
                };
            } while (oconn.State != ConnectionState.Open); // ??? вставить проверку успешности Prepare()

Дополнительно: хотелось бы держать часто выполняемый запрос в ocmd.CommandText открытым (в состоянии Prepared) в течении сессии, чтобы не валить сервер запросами, требующими разбора. В цикле в блоке try/catch выполняются oconn.Open(), затем ocmd.Prepare(). Выход из цикла должен состояться только при условии успешности обоих команд. Я знаю, как проверить успешность только первой из них: oconn.State != ConnectionState.Open

Вопрос: Как проверить, что OracleCommand уже находится в состоянии Prepared для принятия решения, что повторно выдавать запрос на сервер не нужно и можно уже присваивать параметры/выполнять запрос? Метод Prepare() у него есть, а вот свойства Prepared не нашёл. Плохо искал?

Буду признателен за рекомендации или тычок куда смотреть...


Ответы (1 шт):

Автор решения: Alexander Petrov

Комментариев много, а ответа нет. Попробую я его дать.

Нужно рассмотреть две стороны: серверную и клиентскую.


На сервере (СУБД) все запросы парсятся, составляется план и он кэшируется. Далее этот план используется и повторно время не тратится на парсинг sql и его составление. Причём не важно, откуда пришёл этот запрос: например, из приложения на Java или на Python - если он уже есть в кэше, то будет взят оттуда.

Когда-то раньше, в прошлые десятилетия, это было не так. Планы хранимых процедур хранились, а обычных запросов - нет. Вот тогда имели смысл prepared - подготовленные запросы. Можно было явно указать СУБД сохранять план в кэше. С тех пор памяти стало немеряно, движки СУБД изменились, нужда в явном указании исчезла.


Теперь клиентская сторона.

Наличие методов/функций/процедур наподобие prepare раньше было оправдано. Теперь, когда все запросы кэшируются, это стало рудиментом. Если посмотреть по ссылкам: 1, 2 - об этом прямо говорится в документации. Метод есть, но он ничего не делает.

В некоторых языках/фреймворках до сих пор есть такое понятие как prepared statement или prepared query. В других вместо этого существует термин parameterized query. В обоих случаях, это параметризованный запрос.

Суть в том, что параметризованный запрос, хранящийся в СУБД, можно многократно выполнять с разными значениями параметров. При этом он не парсится повторно. То есть он подготовлен (prepared) один раз и на этом всё.


Теперь собственно ответ на ваш вопрос.

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

→ Ссылка