有没有直接的方法将数据加载到内存而不加载数据库服务器?

时间:2018-02-15 06:18:56

标签: c# ado.net bigdata datareader dataadapter

我正在尝试从sql server和oracle rdbms中读取数百万个数据。

Sql Server - select Id as LinkedColumn,CompareColumn from Source order by LinkedColumn
Oracle -select Id as LinkedColumn,CompareColumn from Target order by LinkedColumn

此数据库驻留在不同的服务器上,我想从不同的服务器读取此数据。

因此,想法是尽可能地保持数据库服务器免费。

我想用块读取数百万个数据而不是使用数据读取器读取数据,数据读取器将对数据库执行整个查询,数据库服务器将在内存流中打开这些记录,然后数据读取器将读取记录。 / p>

由于数据库服务器上的负载而导致多个作业占用大量时间。

Records in Source : 12377200

Records in Target : 12266800

由于这个顺序,它花费了太多时间。

那么有没有办法在数据库上执行查询并以某种方式将数据直接存入我的服务器内存(datatable or list or array等),而不会在数据库服务器上加载?

我的下面的代码占用了太多时间(只有2个多小时才能从源和目标中读取数据),以获得2400万条记录。

代码:

public void Test(SqlConnection srcCon, SqlConnection tgtCon)
        {
            int srcChunkSize = 1000;
            int srcCurCount = 1;
            int tgtChunkSize = 1000;
            int tgtCurCount = 1;
            bool srcBreak = false;
            bool tgtBreak = false;
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            var da1 = new SqlDataAdapter(null, srcCon);
            var da2 = new SqlDataAdapter(null, tgtCon);
            da1.SelectCommand.CommandTimeout = 0;
            da2.SelectCommand.CommandTimeout = 0;
            while (true)
            {
                var srcDt = new DataTable();
                var tgtDt = new DataTable();
                if (!srcBreak)
                {
                    string srcQuery = "select Id as LinkedColumn,CompareColumn from Source order by LinkedColumn" +
                                        " OFFSET ((" + srcCurCount + " - 1) * " + srcChunkSize + " ) ROWS FETCH NEXT " + srcChunkSize + " ROWS ONLY;";
                    da1.SelectCommand.CommandText = srcQuery;
                    srcDt = GetDatatable(da1);
                }
                if (!tgtBreak)
                {
                    string tgtQuery = "select Id as LinkedColumn,CompareColumn from Target order by LinkedColumn" +
                                        " OFFSET ((" + tgtCurCount + " - 1) * " + tgtChunkSize + " ) ROWS FETCH NEXT " + tgtChunkSize + " ROWS ONLY;";
                    da2.SelectCommand.CommandText = tgtQuery;
                    tgtDt = GetDatatable(da2);
                }

                if (srcDt.Rows.Count == 0) srcBreak = true;
                srcCurCount++;

                if (tgtDt.Rows.Count == 0) tgtBreak = true;
                tgtCurCount++;

                if (srcBreak && tgtBreak) break;
            }
            stopwatch.Stop();
            string a = stopwatch.Elapsed.ToString(@"d\.hh\:mm\:ss");
            Console.WriteLine(a);
        }

        private DataTable GetDatatable(SqlDataAdapter da)
        {
            DataTable dt = new DataTable();
            da.Fill(dt);
            return dt;
        }

2 个答案:

答案 0 :(得分:0)

如果不知道你的最终目标是什么,很难提供一个好的答案。例如,最佳答案可能是在存储过程中而不是在c#中执行任务。

但是,为了简化您的流程,您可以使用并行编程。这是一个很好的起点:MSDNs parallel processing page

另外,请考虑退一步看看您的架构。您可以从启动图形数据库并从Oracle进行批量导出\导入中受益。图形数据库在复杂的大规模关系查询中效率更高。

答案 1 :(得分:0)

SqlDataReader:

保持连接打开直到我们完成(不要忘记关闭它!)。 通常只能迭代一次 对更新回数据库没有用 另一方面,它: 一次只有一条记录在内存中,而不是整个结果集(这可能很大) 与我们在一次迭代中所能达到的速度一样快 允许我们更快地开始处理结果(一旦第一条记录可用)

SqlDataAdapter/数据集

让我们在完成加载数据后立即关闭连接,甚至可以自动为我们关闭它 所有结果都在内存中可用 我们可以根据需要对其进行多次迭代,甚至可以通过索引查找特定记录 有一些内置的功能可以更新回数据库 代价是: 更高的内存使用 我们等到所有数据都加载完毕再使用任何数据

您可以在此处查看原始帖子: https://medium.com/exam-70-487/data-reader-vs-data-adapter-ede63a5f771e

谢谢。