Почему я получаю предупреждения о закрытии неиспользуемых дескрипторов RODBC?

Я использую RODBC с R и Knitr для составления отчетов с использованием различных производственных баз данных. В некоторых из этих отчетов я выполняю множественные запросы к нескольким базам данных.

Каждый мой запрос выполняется в функции вида:

get.total.orders <- function(db.connex.string, start.date, end.date){
    db.connex <- odbcDriverConnect(db.connex.string)
    ord.qry <- sprintf("SELECT ord_OrderReference AS 'order.ref',
ord_RegisterDate as 'register.date'
FROM Orders
WHERE ord_RegisterDate >= '%s' AND ord_RegisterDate < '%s'",
                       start.date, end.date)
    orders <- sqlQuery(db.connex, ord.qry)
    odbcClose(db.connex)
    return(orders)
}

Обратите внимание, что в этой функции канал ODBC открывается и закрывается, и что между открытием и закрытием канала выполняется только один простой запрос.

Тем не менее, когда я запускаю отчет более одного раза (например, при разработке отчета), я получаю предупреждения, подобные следующим:

Warning: closing unused RODBC handle 41

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

Почему, если я открываю и закрываю канал в функции запроса, у меня остаются открытые, «неиспользуемые» дескрипторы RODBC?

Что еще более важно, как я могу избежать этой проблемы?


person mac    schedule 04.09.2013    source источник
comment
Вы уверены, что odbcClose удалось?   -  person James    schedule 10.02.2014
comment
@ Джеймс Нет, как это проверить?   -  person mac    schedule 10.02.2014
comment
Оберните вызов print вокруг него. Он возвращает значение незаметно: TRUE в случае успеха и FALSE в случае неудачи.   -  person James    schedule 10.02.2014
comment
Я попробую if(odbcClose(db.connex)!=TRUE) warning("ODBC channel not closed") посмотреть, не смогу ли я поймать это, когда это произойдет.   -  person mac    schedule 10.02.2014


Ответы (2)


Я бы избегал этого, используя on.exit:

get.total.orders <- function(db.connex.string, start.date, end.date){
   db.connex <- odbcDriverConnect(db.connex.string)
   on.exit(odbcClose(db.connex))  # <-----------------------   change here
   ord.qry <- sprintf("SELECT ord_OrderReference AS 'order.ref',
      ord_RegisterDate as 'register.date'
         FROM Orders
         WHERE ord_RegisterDate >= '%s' AND ord_RegisterDate < '%s'",
         start.date, end.date)
 orders <- sqlQuery(db.connex, ord.qry)
 return(orders)
 }

Таким образом, соединение будет закрыто даже в случае ошибки. См. также ?on.exit.

[РЕДАКТИРОВАТЬ]

Вышеприведенное предполагает, что дескриптор не был закрыт из-за ошибки при выполнении запроса. Если запрос был в порядке, но дескриптор просто не был закрыт, то я понятия не имею. odbcClose возвращает 0 в случае успеха, так что вы можете это проверить.

[EDIT2]

Как указывали другие, об этом, вероятно, не о чем беспокоиться - с другой стороны, все равно было бы интересно выяснить, почему соединение не закрывается, если вы явно указываете его закрыть. Может быть, это всего лишь вопрос миллисекунд, и запрос еще не завершен, когда результат присваивается. Для меня это не имеет особого смысла, так как если результат присваивается orders, то что еще может быть в базе данных? Но, может быть, что-то есть. В этом случае можно попытаться дать ему еще немного времени, например.

#...
orders <- sqlQuery(db.connex, ord.qry)
orders # or force(orders) - to just evaluate the result once more
Sys.sleep(0.01)  # give it 10 milliseconds
orders # or return(orders) - to return the result
# presuming on.exit as before - so odbcClose will happen here too
}

Это звучит очень глупо, но я не удивлюсь, если это действительно сработает.

Другая идея заключается в том, что если вы используете Rstudio, вы можете получить некоторые фантомные сообщения об ошибках, как это происходит, например, при использовании plot с несуществующим графическим параметром в первый раз, а затем без ошибок во второй раз.

plot(1, bimbo=2)  # here you get some warnings as bimbo is not a graphical parameter
plot(2)   # nothing wrong here but RStudio replays the previous warnings

Возможно, что-то подобное происходит с обработчиками db — если это так, было бы поучительно посмотреть, получаете ли вы одинаковые предупреждения как в RStudio, так и в консоли (Rgui или Rterm в Windows или запуск R в терминале в Linux). Это, конечно, применимо, если вы используете Rstudio.

И, наконец, вы можете попробовать опубликовать это на r-help, поскольку Брайан Рипли (один из авторов RODBC) присутствует там, но не здесь.

Так что, как видите, у меня нет реального ответа, и если для его выяснения требуется слишком много усилий, я бы рекомендовал не беспокоиться об этом :)

person lebatsnok    schedule 06.02.2014
comment
полезно знать трюк on.exit(), но в этом случае запросы выполняются успешно. - person mac; 10.02.2014

Функция odbcClose() завершится ошибкой, если в соединении есть открытые транзакции. В этом случае это соединение останется открытым.

person Mayou    schedule 04.09.2013
comment
разве обработка не серийная? Как бы выполнение достигло odbcClose(), если бы в соединении все еще были транзакции (предположительно из вызова sqlQuery())? В любом случае, как я могу избежать этой проблемы? - person mac; 04.09.2013
comment
Странно то, что я выполнил ваш код в точности как есть (конечно, используя аналогичный запрос для одной из моих таблиц), и он не дает мне никаких предупреждений о закрытии неиспользуемых дескрипторов. Однако я запускал этот запрос несколько раз. раз в одной и той же базе данных.. - person Mayou; 04.09.2013
comment
Предупреждения приходят позже, если вы оцениваете код несколько раз. По-видимому, есть процедура сборки мусора, которая через некоторое время закрывает неиспользуемые соединения. К сожалению, AFAIK, нет возможности перечислить все открытые соединения, чтобы быстро проверить, было ли соединение закрыто / какие соединения остаются открытыми. - person mac; 04.09.2013
comment
Да, неиспользуемые соединения действительно закрываются gc(), иногда это происходит при вызове функции, иногда позже. Однако предупреждение не о чем беспокоиться. - person Mayou; 04.09.2013
comment
@mdsumner showConnections(all=TRUE) не отображает соединения RODBC. - person mac; 05.09.2013