【问题标题】:How to avoid making multiple connections to postgres database when accessing using R使用 R 访问时如何避免与 postgres 数据库建立多个连接
【发布时间】:2021-03-29 00:21:50
【问题描述】:

我正在使用以下代码,但是它在调用 map 函数时创建了多个连接并且它们没有关闭。结果,我的 rds 数据库被连接淹没了。有什么办法可以更改此代码以防止出现如此多的连接?

   connect.to.database <- function (dbname, schema = "public", host, port, user, pass) {
      con <- dbConnect(RPostgres::Postgres(),
                       dbname = dbname,
                       user = user,
                       password = pass,
                       host = host,
                       port = port)
      
      
      # this puts the schema in the search path, which means that instead of
      # having to use <schema name>.<table name> you can just write <table name>
      res <- dbSendQuery(con, paste0("SET search_path TO ",
                                     dbQuoteIdentifier(con, schema),
                                     ", public"))
      
      # check for errors
      dbFetch(res)
      dbClearResult(res)
      
      con
    }

    schemas <- dbGetQuery(connect.to.database(dbname, "public", host, port, user, password), paste0("SELECT schema_name FROM information_schema.schemata"))
    
    schema_names <- schemas %>% pull()
    
    schemas_tables <- map(.x = schema_names,~dbGetQuery(connect.to.database(dbname, "public", host, port, user, password), paste0("SELECT table_name FROM information_schema.tables WHERE table_schema = ","'",.x,"'")) %>% mutate(schema_name = .x)) %>%
                      bind_rows()

【问题讨论】:

  • 考虑使用pooldb.rstudio.com/pool
  • 你明确地dbConnect,但从来没有dbDisconnect。也许我错过了一些东西,但你是在对自己做。考虑在map 中调用con &lt;- connect.to.database(...) *outside`,然后在map 中使用con

标签: sql r dbi rpostgres


【解决方案1】:

创建一个全局连接对象并在map 中使用。 (我从您的第一个查询中删除了不必要的 paste0。)

conn <- connect.to.database(dbname, "public", host, port, user, password)
schema <- dbGetQuery(conn, "SELECT schema_name FROM information_schema.schemata")

schemas_tables <- map(
  .x = schema$schema_name,
  ~ dbGetQuery(conn, paste0("SELECT table_name FROM information_schema.tables WHERE table_schema = ","'",.x,"'")) %>%
    mutate(schema_name = .x)
) %>%
  bind_rows()

您可能需要考虑参数化查询,而不是手动构建查询字符串。虽然存在对恶意 SQL injection(例如 XKCD 的 Exploits of a Mom aka “Little Bobby Tables”)的安全担忧,但它也是对格式错误的字符串或 Unicode-vs-ANSI 错误的担忧,即使它是单个数据分析师运行询问。 DBI(带有odbc)和RODBC都支持parameterized queries,无论是原生还是通过插件。

这将更改为:

schemas_tables <- map(
  .x = schema$schema_name,
  ~ dbGetQuery(conn, "SELECT table_name FROM information_schema.tables WHERE table_schema = ?",
               params = list(.x)) %>%
    mutate(schema_name = .x)
) %>%
  bind_rows()

但坦率地说,我认为使用IN 而不是= 可能更容易。同样,使用参数绑定。

schemas_tables <- dbGetQuery(conn, "SELECT table_name FROM information_schema.tables WHERE table_schema IN (?)",
                             params = list(schema$schema_name))

(不需要map。)

或者我相信您可以在一个查询中完成,而不是两个。

dbGetQuery(conn, "
    select table_name
    from information_schema.tables
    where table_schema in (
      select schema_name from information_schema.schemata
    )")

记住

...完成后关闭连接。

dbDisconnect(conn)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-17
    相关资源
    最近更新 更多