sql - 使用 R 访问时如何避免与 postgres 数据库建立多个连接
问题描述
我正在使用以下代码,但是它在调用 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()
解决方案
创建单个全局连接对象并在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 注入的安全问题(例如,XKCD 的Exploits of a Mom又名“Little Bobby Tables”),但它也是对格式错误的字符串或 Unicode-vs-ANSI 错误的问题,即使它是单个数据分析师运行询问。DBI
(with odbc
) 和RODBC
支持参数化查询,无论是本机还是通过附加组件。
这会将其更改为:
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)
推荐阅读
- android - 列表未在删除项目上发出 (RxKotlin)
- reactjs - 如何使用 react-native 打开列表中的键盘
- java - 使用 Java、Spring 发出 Oauth2 请求
- python - Scrapy - 在第一次请求后收到 504 网关超时
- java - 是否可以缩写删除变量的java函数?
- c# - 是否推荐/可以接受将 async void 方法运行到新线程中?
- git - 为什么当我在“X”分支中进行更改时,我的主分支也会以同样的方式发生变化?
- vba - 如何使用 Windows 任务计划程序每周一运行 Excel 宏
- docker - Docker run mapping ports does not work in ubuntu 16.04
- python - 在虚拟环境中设置不同版本的python