在内存中加载大量结果集的最佳方法是什么?

ILo*_*low 6 c# ado.net datareader bigdata

我正在尝试加载来自不同RDBMS的2个巨大的结果集(源和目标),但我正在努力的问题是在内存中获得这2个巨大的结果集.

下面考虑从源和目标中提取数据的查询:

Total jobs running in parallel = 3

Time taken by Job1 = 01:47:25

Time taken by Job1 = 01:47:25

Time taken by Job1 = 01:48:32

There is no index on Id Column.
Run Code Online (Sandbox Code Playgroud)

来源: 12377200

目标记录: 12266800

以下是我尝试过的一些统计方法:

1)2个开放数据读取器方法,用于读取源和目标数据:

   Total jobs = 1
   Chunk size : 100000
   Time Taken : 02:02:48
   There is no index on Id Column.
Run Code Online (Sandbox Code Playgroud)

select Id as LinkedColumn,CompareColumn from Source order by LinkedColumn 这很糟糕.

2)通过块读取方法来读取源和目标数据的块:

   Total jobs = 1
   Chunk size : 100000
   Time Taken : 00:39:40
   Index is present on Id column.
Run Code Online (Sandbox Code Playgroud)

3)通过块读取方法读取源和目标数据的块:

   Total jobs = 1
   Index : Yes
   Time: 00:01:43
Run Code Online (Sandbox Code Playgroud)

4)2个开放式数据读取器方法,用于读取源和目标数据:

   Total jobs running in parallel = 3
   Index : Yes
   Time: 00:25:12
Run Code Online (Sandbox Code Playgroud)

5)2个开放数据读取器方法,用于读取源和目标数据:

Source Sql Query Execution time in sql server management studio: 00:01:41

Target Sql Query Execution time in sql server management studio:00:01:40
Run Code Online (Sandbox Code Playgroud)

我确实观察到虽然在LinkedColumn上有索引确实提高了性能,但问题是我们正在处理可能具有索引或可能没有索引的第三方RDBMS表.

我们希望保持数据库服务器尽可能免费,因此数据读取器方法似乎并不是一个好主意,因为会有大量并行运行的作业,这将给我们不想要的数据库服务器带来如此大的压力.

因此,我们希望从源到目标获取资源内存中的记录,并进行1-1比较记录比较,保持数据库服务器空闲.

注意:我想在我的c#应用程序中执行此操作,并且不想使用select Id as LinkedColumn,CompareColumn from Target order by LinkedColumnvar dr = command.ExecuteReader();.

更新:

源Sql查询在sql server management studio中的执行时间:00:01:41

目标Sql查询sql server management studio中的执行时间:00:01:40

在内存中读取大量结果集的最佳方法是什么?

代码:

static void Main(string[] args)
        {   
            // Running 3 jobs in parallel
             //Task<string>[] taskArray = { Task<string>.Factory.StartNew(() => Compare()),
        //Task<string>.Factory.StartNew(() => Compare()),
        //Task<string>.Factory.StartNew(() => Compare())
        //};
            Compare();//Run single job
            Console.ReadKey();
        }
public static string Compare()
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            var srcConnection = new SqlConnection("Source Connection String");
            srcConnection.Open();
            var command1 = new SqlCommand("select Id as LinkedColumn,CompareColumn from Source order by LinkedColumn", srcConnection);
            var tgtConnection = new SqlConnection("Target Connection String");
            tgtConnection.Open();
            var command2 = new SqlCommand("select Id as LinkedColumn,CompareColumn from Target order by LinkedColumn", tgtConnection);
            var drA = GetReader(command1);
            var drB = GetReader(command2);
            stopwatch.Stop();
            string a = stopwatch.Elapsed.ToString(@"d\.hh\:mm\:ss");
            Console.WriteLine(a);
            return a;
        }
      private static IDataReader GetReader(SqlCommand command)
        {
            command.CommandTimeout = 0;
            return command.ExecuteReader();//Culprit
        }
Run Code Online (Sandbox Code Playgroud)

Jer*_*son 5

(据我所知)没有什么比DataReader更快的用于获取数据库记录的。

使用大型数据库面临很多挑战,在不到2秒的时间内读取1000万条记录非常好。

如果您想更快一点,可以:

  1. jdwend的建议:

使用sqlcmd.exe和Process类运行查询并将结果放入csv文件中,然后将csv读入c#。sqlcmd.exe旨在存档大型数据库,并且运行速度比c#接口快100倍。使用linq方法也比SQL Client类更快

  1. 并行查询并获取合并结果:https ://shahanayyub.wordpress.com/2014/03/30/how-to-load-large-dataset-in-datagridview/

  2. 最简单的方法(对于SELECT *全部而言,IMO最好的方法)是向其扔硬件:https : //blog.codinghorror.com/hardware-is-cheap-programmers-are-expensive/

还要确保您正在发布模式下在PROD硬件上进行测试,因为这可能会使基准测试产生偏差。