dbplyr filter() 和惰性求值
dbplyr filter() and lazy evaluation
我有一个很大的 MySQL table(92 列,300 万行),我在 R 中与 dbplyr
争论不休。我是这个包的新手,对 dbplyr
的惰性评估有一个或两个问题,因为我遇到了一些相当缓慢的问题。
假设我已连接到我的数据库并希望执行 select
操作以减少列数:
results<- my_conn_table %>%
select(id, type, date)
尽管有数百万行,但查看 results
几乎是瞬时的(为清楚起见只显示 3 行):
> results
# Source: lazy query [?? x 3]
# Database: mysql []
id type date
<int> <chr> <date>
1 1 Customer 1997-01-04
2 2 Customer 1997-02-08
3 3 Business 1997-03-29
...
但是,如果我尝试执行过滤操作:
results<- my_df %>%
select(id, type, date) %>%
filter(type == "Business")
该操作需要非常 的处理时间(在某些情况下需要数十分钟)。这么长的处理时间是 nrow ~= 300 万的简单函数吗? (换句话说,我对此无能为力,因为数据集很大。)或者有人可以提出一些通用方法来提高性能吗?
我最初对惰性评估的理解是 filter()
查询只会 return 前几行,以防止长时间 运行 的情况。如果我想要所有数据,我可以 运行 collect()
将结果收集到我的本地 R 会话中(我 会 预计会花费大量时间,具体取决于在查询中。)
您可以尝试的一件事是 运行 相同的查询,但使用 DBI
包:
res <- DBI::dbSendQuery(con, "SELECT id,type,date FROM your_table_name WHERE type = 'business'")
如果速度一样,就是你的数据。如果不是,则为 dbplyr
。您也可以尝试使用不同的过滤器参数(可以指定一个 ID 或日期,看看需要多长时间),看看问题是否仍然存在。
基于@NovaEthos 的回答,您可以调用 show_query(results)
来获取 dbplyr 生成并传递给数据库的 SQL 查询。在此处发布此查询将清楚查询数据库的方式是否效率低下。
要调查的另一件事是数据的索引方式。就像书中的索引一样,数据库中的索引 table 有助于更快地查找记录。
您可能只需要 type = 'business'
的 1000 条记录,但如果这些记录仅从第 200 万行开始,那么计算机必须扫描三分之二的数据才能找到第一条感兴趣的记录.
您可以使用如下方式向现有数据库 table 添加索引:
query <- paste0("CREATE NONCLUSTERED INDEX my_index_name ON", database_name, ".", schema_name, ".", table_name, "(", column_name, ");")
DBI::dbExecute(db_connection, as.character(query))
请注意,此语法适用于 SQL 服务器。您的数据库可能需要稍微不同的语法。在实践中,我将其包装在一个带有额外检查的函数中,例如 'does the indexing column exist in the table?' 这已被证明 here.
我有一个很大的 MySQL table(92 列,300 万行),我在 R 中与 dbplyr
争论不休。我是这个包的新手,对 dbplyr
的惰性评估有一个或两个问题,因为我遇到了一些相当缓慢的问题。
假设我已连接到我的数据库并希望执行 select
操作以减少列数:
results<- my_conn_table %>%
select(id, type, date)
尽管有数百万行,但查看 results
几乎是瞬时的(为清楚起见只显示 3 行):
> results
# Source: lazy query [?? x 3]
# Database: mysql []
id type date
<int> <chr> <date>
1 1 Customer 1997-01-04
2 2 Customer 1997-02-08
3 3 Business 1997-03-29
...
但是,如果我尝试执行过滤操作:
results<- my_df %>%
select(id, type, date) %>%
filter(type == "Business")
该操作需要非常 的处理时间(在某些情况下需要数十分钟)。这么长的处理时间是 nrow ~= 300 万的简单函数吗? (换句话说,我对此无能为力,因为数据集很大。)或者有人可以提出一些通用方法来提高性能吗?
我最初对惰性评估的理解是 filter()
查询只会 return 前几行,以防止长时间 运行 的情况。如果我想要所有数据,我可以 运行 collect()
将结果收集到我的本地 R 会话中(我 会 预计会花费大量时间,具体取决于在查询中。)
您可以尝试的一件事是 运行 相同的查询,但使用 DBI
包:
res <- DBI::dbSendQuery(con, "SELECT id,type,date FROM your_table_name WHERE type = 'business'")
如果速度一样,就是你的数据。如果不是,则为 dbplyr
。您也可以尝试使用不同的过滤器参数(可以指定一个 ID 或日期,看看需要多长时间),看看问题是否仍然存在。
基于@NovaEthos 的回答,您可以调用 show_query(results)
来获取 dbplyr 生成并传递给数据库的 SQL 查询。在此处发布此查询将清楚查询数据库的方式是否效率低下。
要调查的另一件事是数据的索引方式。就像书中的索引一样,数据库中的索引 table 有助于更快地查找记录。
您可能只需要 type = 'business'
的 1000 条记录,但如果这些记录仅从第 200 万行开始,那么计算机必须扫描三分之二的数据才能找到第一条感兴趣的记录.
您可以使用如下方式向现有数据库 table 添加索引:
query <- paste0("CREATE NONCLUSTERED INDEX my_index_name ON", database_name, ".", schema_name, ".", table_name, "(", column_name, ");")
DBI::dbExecute(db_connection, as.character(query))
请注意,此语法适用于 SQL 服务器。您的数据库可能需要稍微不同的语法。在实践中,我将其包装在一个带有额外检查的函数中,例如 'does the indexing column exist in the table?' 这已被证明 here.