【问题标题】:Taking lot of time to read from SQL Server using c#使用 c# 花费大量时间从 SQL Server 读取
【发布时间】:2013-08-01 06:19:49
【问题描述】:

我的表中有 400 万行。(大小约为 300 GB),我想从 sql server 数据库中读取表中的所有行。我在 C# 中使用了以下代码。这需要时间。请给我一些改进建议。

            List<int> hit_block_index = new List<int>();

            /* Here i process some other and populate hit_block_index with integers */

            string _query = "SELECT TraceName,BlockVector FROM Trace";

            SqlConnection _connection = new SqlConnection(connection_string);

            _connection.Open();

            SqlCommand _command = new SqlCommand(_query, _connection);

            SqlDataReader data_reader = _command.ExecuteReader();

            Byte[] block_vector=null;

            string trace_name = null;

            BitArray trace = null;

            int max_coverage = 0;

            while (data_reader.Read())
            {
                  int coverage = 0;

                  block_vector = (byte[])data_reader["BlockVector"];

                  trace_name = (string)data_reader["TraceName"];

                  BitArray trace = new BitArray(block_vector);

                  foreach (int x in hit_blocks_index)
                  {
                       if (trace[x])
                       {
                           coverage++;
                       }
                  }

                  Console.WriteLine("hit count is:" + coverage);

                  if (coverage > max_coverage)
                  {
                         most_covered_trace = trace_name;
                         most_covered_array = trace;
                         max_coverage = coverage;
                  }
           }

【问题讨论】:

  • 300 GB 应该需要一些时间,如果没有,我会担心
  • 改进#1:降低预期。
  • 即使 300GB 的原始数据通过千兆链路(没有传输开销)仍然是 (300&lt;&lt;30)*8 / (10**9) / 60.0 = 42.9 分钟。如果将磁盘 I/O、TCP 开销、SQL 处理时间等因素考虑在内,我认为 3 小时一点也不差。
  • 哦,在这种情况下,在BlockVector 列上运行ProcessByteArray() SQL 函数。 &lt;/sarcasm&gt; - 如果您需要帮助,您需要告诉我们,具体您正在对数据做什么
  • 甚至没有任何where 条件可以过滤数据,因此我认为 3 小时非常适合您的场景。 :)

标签: c# sql sql-server-2008 sql-server-2012


【解决方案1】:

这样的事情可能会奏效。我还不确定效率 - 这可能取决于您正在寻找的点击量:

create type HitBlocks as table (
    HitIndex int not null
)
go
create procedure FindMaxCover
    @Hits HitBlocks readonly
as
    ;With DecomposedBlocks as (
        select (HitIndex/8)+1 as ByteIndex,POWER(2,(HitIndex%8)) as BitMask
        from @Hits
    ), Coverage as (
        select
            t.TraceName,SUM(CASE WHEN SUBSTRING(t.BlockVector,db.ByteIndex,1) & BitMask != 0 THEN 1 ELSE 0 END) as Coverage
        from
            Trace t
                cross join
            DecomposedBlocks db
        group by
            t.TraceName
    ), Ranked as (
        select *,RANK() OVER (ORDER BY Coverage desc) as rk
        from Coverage
    )
    select
        t.TraceName,
        t.BlockVector,
        r.Coverage
    from
        Ranked r
            inner join
        Trace t
            on
                r.TraceName = t.TraceName
    where rk = 1

目前,如果有多个具有相同覆盖级别的结果,这将返回多行。您可能还需要调整 a) 我的期望与您的期望之间的一些错误,以及 b) 在计算正确的 BitMask 值时可能存在一些字节顺序问题。

从您的代码中,您将使用您当前存储在hit_block_index 中的值填充DataTable,并将其作为@Hits parameter 传递。

【讨论】:

    【解决方案2】:

    如果您真的必须读取所有数据...通过 StoredProcedure 或您的引擎允许的任何方式将您的代码放入数据库。完全传输数据库是没有意义的。

    除此之外,您真的应该考虑选择另一种策略。 示例 1:您可以在插入时创建触发器。在插入一个值时,您可以在不读取所有数据的情况下重新计算覆盖率(如果可能) 示例 2:您可以使用 SQL Azure Federations 或 Azure Worker Role - 来扩展您的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-10
      • 1970-01-01
      • 2015-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多