通过RStudio中的JDBC连接将大表拆分为2个数据帧

时间:2016-06-20 03:49:13

标签: sql r

通过R我连接到远程持有的数据库。我遇到的问题是我的硬件不是很好,数据集包含数千万行,每个表大约有10列。当我运行下面的代码时,在df步骤,我从R:

得到一个“没有足够的RAM”错误
library(DatabaseConnector)
conn <- connect(connectionDetails)
df <- querySql(conn,"SELECT * FROM Table1")

我想做的是将表分成两部分,根据需要进行过滤/分析/组合。我因为我使用conn JDBC连接我必须使用SQL语法才能使它工作。使用SQL,我从下面的代码开始:

df <- querySql(conn,"SELECT TOP 5000000 FROM Table1")

然后我遇到的问题是如何创建第二个数据帧,从n - 5000000行开始,到最后一行结束,从Table1中检索。

我愿意接受建议,但我认为这个问题有两个可能的答案。第一个是在querySql中工作以使其工作。第二种是使用querySql以外的R函数(不知道这会是什么样子)。由于工作环境,我仅限于R.

1 个答案:

答案 0 :(得分:1)

SQL语句

SELECT TOP 5000000 * from Table1

没有按照你的想法去做。

关系表是conceptually unordered

  

关系被定义为一组n元组。在数学和关系数据库模型中,集合是唯一的非重复项目的无序集合,尽管某些DBMS对其数据强加了一个订单。

从表中选择会产生结果集。结果集在概念上也是无序的,除非你明确指定它们的顺序,这通常是使用order by子句完成的。

当您使用top(或limit,具体取决于DBMS)子句来减少查询返回的记录数时(让我们将这些称为&#34) ;返回记录&#34;)以下该查询返回的可能的记录数量(让我们将这些记录称为&#34;所选记录&#34 ;)如果你没有指定一个order by子句,那么它在概念上是不可预测的,随机选择哪个选定的记录作为返回的记录。

由于您未在查询中指定order by子句,因此您实际上从表中获取了5,000,000条不可预测且随机的记录。每次运行查询时,您可能会得到一组不同的5,000,000条记录(从概念上讲,至少是这样)。

因此,询问如何获得第二个结果集&#34;从n - 5000000开始到结束最后一行&#34;是没有意义的。没有n,也没有最后一行。返回记录的选择不是确定性的,DBMS不记得过去查询的这种选择。将此类信息合并到后续查询中的唯一可能方式是将其明确地包含在SQL中,例如在id列上使用not in条件并将第一个查询中的id值嵌入为文字,或者再做一些负面连接,涉及将id值嵌入为文字。但显然这是不合理的。

这里有两种可能的解决方案。

1: order by limitoffset

看看PostgreSQL documentation on limit and offset。首先,为了强调缺乏秩序的观点,请注意以下段落:

  

使用LIMIT时,使用ORDER BY子句将结果行限制为唯一顺序非常重要。否则,您将获得查询行的不可预测的子集。您可能会要求第十到第二十行,但第十到第二十行是什么排序?除非您指定ORDER BY

,否则排序未知      

查询优化器在生成查询计划时会考虑LIMIT,因此您很可能会得到不同的计划(产生不同的行顺序),具体取决于您为LIMIT和{{1}提供的内容}。因此,使用不同的OFFSET / LIMIT值来选择查询结果的不同子集会产生不一致的结果,除非您使用OFFSET强制执行可预测的结果排序。这不是一个bug;这是SQL不承诺以任何特定顺序传递查询结果这一事实的固有后果,除非ORDER BY用于约束订单。

现在,此解决方案要求您指定完全命令结果集的ORDER BY子句。只有部分命令结果集的order by子句是不够的,因为它仍然会留有一些不可预测性和随机性的空间。

获得order by子句后,您可以使用相同的order by值并增加limit值来重复查询。

这样的事情:

offset

2:合成编号列并对其进行过滤

可以在select子句中添加一列,它将为结果集提供完整的顺序。通过将此SQL包装在子查询中,您可以对新列进行过滤,从而实现自己的数据分页。事实上,这个解决方案可能稍微强大一些,因为理论上你可以选择不连续的记录子集,尽管我从来没有见过任何人真正这样做过。

要计算排序列,您可以使用select * from table1 order by id1, id2, ... limit 5000000 offset 0; select * from table1 order by id1, id2, ... limit 5000000 offset 5000000; select * from table1 order by id1, id2, ... limit 5000000 offset 10000000; ... 分区功能。

重要的是,您仍然需要指定用于对分区进行排序的id列。在任何可以想象的解决方案中这是不可避免的;总是必须有一些确定性的,可预测的记录顺序来指导无状态的数据分页。

这样的事情:

row_number()

显然,这个解决方案比前一个解决方案更复杂,更冗长。以前的解决方案可能允许在更加手动的分区和过滤方法下进行性能优化。因此,我会推荐以前的解决方案。

我上面的讨论主要关注PostgreSQL,但其他DBMS应该提供相同的功能。例如,对于SQL Server,请参阅Equivalent of LIMIT and OFFSET for SQL Server?,其中显示了合成编号解决方案的示例,并且还指出(至少从SQL Server 2012开始)您可以使用select * from (select *, row_number() over (id1, id2, ...) rn from table1) t1 where rn>0 and rn<=5000000; select * from (select *, row_number() over (id1, id2, ...) rn from table1) t1 where rn>5000000 and rn<=10000000; select * from (select *, row_number() over (id1, id2, ...) rn from table1) t1 where rn>10000000 and rn<=15000000; ... 和{{1}实现限制/偏移功能。