left_join 和 dbplyr 效率低下 SQL
left_join and dbplyr inefficient SQL
我正在从多个不同的 table 中提取数据并将它们连接到一个基础 table 中,如下所示:
df <- tbl(ch, dbplyr::in_schema("schem1", 'education_data')) %>%
select(ID, ProviderKey,ReportingPeriodKey,EthnicityKey) %>%
left_join(
tbl(ch, dbplyr::in_schema("data_schem", 'ReportingPeriodDimensions')) %>%
select(ReportingPeriodKey,ReportingYear),
by = "ReportingPeriodKey"
) %>%
left_join(
tbl(ch, dbplyr::in_schema("data_schem", 'ProviderDimensions')) %>%
select(ProviderKey, ProviderName),
by = "ProviderKey"
) %>%
left_join(
tbl(ch, dbplyr::in_schema("sdr", 'EthnicityDim')) %>%
select(EthnicityKey,Ethnicity_description),
by = "EthnicityKey"
) %>%
filter(ReportingYear %in% ("2015","2016","2017"))
当我用 show_query(df)
检查 SQL 代码时,有一个 'SELECT' SQL 基本命令 table 'education_data' 和为执行的每个连接选择的所有变量,在本例中为 3x。我经常需要加入大约 8 或 9 个其他 table,具体取决于我需要加入的维数 table。
这似乎效率很低,尤其是当我将 table 的记录 运行 拉到数百万时。使用 R 命令而不是直接编码 SQL 是否有任何解决方法?
我猜测,而不是看到整齐的 SQL 查询看起来像:
SELECT a.col1, a.col2, b.col3, c.col4
FROM table_A AS a
LEFT JOIN table_B AS b
ON a.col = b.col
LEFT JOIN table_C AS c
ON b.col = c.col
您看到的嵌套查询看起来更像:
SELECT LHS.col1, LHS.col2, LHS.col3, RHS.col4
FROM (
SELECT LHS.col1, LHS.col2, RHS.col3
FROM table_A AS LHS
LEFT JOIN table_B AS RHS
ON LHS.col = RHS.col
) AS LHS
LEFT JOIN table_C AS RHS
ON LHS.col = RHS.col
但是布局更差。
我同意第一个示例的格式更好,更易于阅读,并且是良好的编码习惯。相比之下,dbplyr 自动生成的 SQL 代码相当难看。
一般来说我不担心这个。人类编写的 SQL 代码旨在是人类和机器可读的。来自 dbplyr 的自动生成的 SQL 代码主要是为了机器可读。您的 SQL 解释器很可能会以相同的方式执行这两个变体。随着我使用 dbplyr 工作的复杂性增加,我相信 SQL 解释器可以找到一种有效的方法来执行查询。
我从未注意到从 dbplyr 自动生成的 SQL 与等效的人工整理代码之间的主要性能差异。但是我没有对此进行广泛的测试。如果你做 运行 这样的测试,它们将是添加到这个问题的一个很好的答案。
如果您担心性能,可以做一些事情:
按照@danblack 的建议,确保您的 table 在您要加入的列上有索引。也许是最重要的列上的聚簇索引。在不离开 R 的情况下执行此操作的一种方法是 DBI::dbExecute("sql string for adding an index goes here")
,它将执行您在数据库中提供的命令。
将关键中间 table 写入数据库和索引。例如,如果 table A 是通过加入 tables B 和 C 组成的,那么如果从 tables B 和 C 直接,但如果您已将 table A 写入数据库 ( A-A ),则只有一个连接。
根据上下文,您可以在加入之前对每个 table 进行分区,然后将输出 table 附加在一起。例如,在 R 中使用循环 运行 每个报告年度的一个查询。 运行 连接较小的输入数据集往往会执行得更快。
我正在从多个不同的 table 中提取数据并将它们连接到一个基础 table 中,如下所示:
df <- tbl(ch, dbplyr::in_schema("schem1", 'education_data')) %>%
select(ID, ProviderKey,ReportingPeriodKey,EthnicityKey) %>%
left_join(
tbl(ch, dbplyr::in_schema("data_schem", 'ReportingPeriodDimensions')) %>%
select(ReportingPeriodKey,ReportingYear),
by = "ReportingPeriodKey"
) %>%
left_join(
tbl(ch, dbplyr::in_schema("data_schem", 'ProviderDimensions')) %>%
select(ProviderKey, ProviderName),
by = "ProviderKey"
) %>%
left_join(
tbl(ch, dbplyr::in_schema("sdr", 'EthnicityDim')) %>%
select(EthnicityKey,Ethnicity_description),
by = "EthnicityKey"
) %>%
filter(ReportingYear %in% ("2015","2016","2017"))
当我用 show_query(df)
检查 SQL 代码时,有一个 'SELECT' SQL 基本命令 table 'education_data' 和为执行的每个连接选择的所有变量,在本例中为 3x。我经常需要加入大约 8 或 9 个其他 table,具体取决于我需要加入的维数 table。
这似乎效率很低,尤其是当我将 table 的记录 运行 拉到数百万时。使用 R 命令而不是直接编码 SQL 是否有任何解决方法?
我猜测,而不是看到整齐的 SQL 查询看起来像:
SELECT a.col1, a.col2, b.col3, c.col4
FROM table_A AS a
LEFT JOIN table_B AS b
ON a.col = b.col
LEFT JOIN table_C AS c
ON b.col = c.col
您看到的嵌套查询看起来更像:
SELECT LHS.col1, LHS.col2, LHS.col3, RHS.col4
FROM (
SELECT LHS.col1, LHS.col2, RHS.col3
FROM table_A AS LHS
LEFT JOIN table_B AS RHS
ON LHS.col = RHS.col
) AS LHS
LEFT JOIN table_C AS RHS
ON LHS.col = RHS.col
但是布局更差。
我同意第一个示例的格式更好,更易于阅读,并且是良好的编码习惯。相比之下,dbplyr 自动生成的 SQL 代码相当难看。
一般来说我不担心这个。人类编写的 SQL 代码旨在是人类和机器可读的。来自 dbplyr 的自动生成的 SQL 代码主要是为了机器可读。您的 SQL 解释器很可能会以相同的方式执行这两个变体。随着我使用 dbplyr 工作的复杂性增加,我相信 SQL 解释器可以找到一种有效的方法来执行查询。
我从未注意到从 dbplyr 自动生成的 SQL 与等效的人工整理代码之间的主要性能差异。但是我没有对此进行广泛的测试。如果你做 运行 这样的测试,它们将是添加到这个问题的一个很好的答案。
如果您担心性能,可以做一些事情:
按照@danblack 的建议,确保您的 table 在您要加入的列上有索引。也许是最重要的列上的聚簇索引。在不离开 R 的情况下执行此操作的一种方法是
DBI::dbExecute("sql string for adding an index goes here")
,它将执行您在数据库中提供的命令。将关键中间 table 写入数据库和索引。例如,如果 table A 是通过加入 tables B 和 C 组成的,那么如果从 tables B 和 C 直接,但如果您已将 table A 写入数据库 ( A-A ),则只有一个连接。
根据上下文,您可以在加入之前对每个 table 进行分区,然后将输出 table 附加在一起。例如,在 R 中使用循环 运行 每个报告年度的一个查询。 运行 连接较小的输入数据集往往会执行得更快。