如何通过表中的块数据获取块?

时间:2016-12-20 08:02:37

标签: c# mysql linq ado.net

我试图通过MySQL表中的块数据来获取块。

我有一张如下表:

HistoryLogs = 10986119

现在我想通过MyQSL中的块数据获取块,并将其传递给sqlbulk副本进行处理。我已将批量大小确定为 1000

例如,如果我有10000的记录,那么我的查询将如下所示:

SELECT * FROM tbl LIMIT 0,1000;
SELECT * FROM tbl LIMIT 1000,2000;
SELECT * FROM tbl LIMIT 2000,3000;
SELECT * FROM tbl LIMIT 9000,10000;

首先,我将从表中获取总记录,然后尝试如下:

 private int FetchCount(string table)
        {
            using (MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM " + table, conn))
            {
                cmd.CommandTimeout = 0;
                return cmd.ExecuteNonQuery();
            }
        }

string query = string.Empty;
string table ="HistoryLogs";
int records = FetchCount(table);
for (int i = 0; i < records / 1000 ; i++) //
 {
     here I would like to create chunk by chunk query and pass it to Process method
 }


 private MySqlDataReader Process(MySqlConnection conn, string query)
        {
            using (MySqlCommand cmd = new MySqlCommand(query, conn))
            {
                cmd.CommandTimeout = 0;
                MySqlDataReader reader = cmd.ExecuteReader();
                return reader;
            }
        }

所以我没有得到如何创建分页查询,也不知道我是否正在以正确的方式思考。

1 个答案:

答案 0 :(得分:2)

您想用什么技术从数据库中获取数据有点不确定。

由于Linq关键字,我假设你想要一个Linq语句,它给你一个带有给定pageSize的项目页面。

然而,您不确定如何获取第X页的数据。您是否有想要分成页面的记录的IQueryable(如在实体框架中 - 强烈推荐),或者您想要更改SQL语句使它会给你页面X?

IQueryable方法

假设您需要类型为T的记录页,并且您有一个IQueryable<T>来获取T类型的所有记录。

 IQueryable<T> allRecords = ...;

您想将此序列划分为多个页面。每个页面都有PageSizePageNr和一系列记录:

class Page<T>
{
    public int PageSize {get; set;}
    public int PageNr {get; set;}
    public IEnumerable<T> Contents {get; set;}
}

现在将AllRecords分成一系列页面,我使用扩展方法:

public static class PagingExtensions
{
    public static IQueryable<Page<T>> ToPages(this IQueryable<T> allRecords, int pageSize)
    {
        return allRecords.Select( (record, i) => new
        {
            PageNr = i / pageSize,
            Record = record,
        })
        .GroupBy(item => item.PageNr)
        // intermediate result: sequence of IGrouping<int, T>
        // where key is pageNr
        // and each element in the group are the records for this page
        .Select(group => new Page<T>()
        {
            PageNr = group.Key,
            PageSize = pageSize,
            Contents = (IEnumerable<T>) group;
        };
    }
}

将MyRecords序列划分为页面的代码为:

const int pageSize = 1000;
IQueryable<MyRecord> allMyRecords = ...
IQueryable<Page<MyRecord>> pages = allMyRecords.ToPages(1000);

// do what you want with the pages, for example:
foreach (Page<MyRecord> page in pages)
{
    Console.WriteLine($"Page {page.PageNr}");
    foreach (MyRecord record in Page.Contents)
    {
       Console.WriteLine(record.ToString());
    }
}

请注意,所有使用的函数都使用延迟执行。在您枚举记录之前,不会获取记录。

如果您希望能够在本地内存而不是数据库中的页面中划分集合,请使用IEnumerable<T>而不是IQueryable<T>

没有IQueryable的方法

如果您没有IQueryable来获取所有记录,您必须创建一个自己实现此类的类,或者根据您要获取的页面调整SQL查询。我不推荐第一种方法。

class Page<T>
{
    public Page(SqlConnection conn, int pageNr, int pageSize)
    {
        this.PageNr = pageNr;
        this.PageSize = pageSize;
    }
    private readonly SqlConnection conn;
    public int PageSize {get; private set;}
    public int PageNr {get; private set;}

    public IEnumerable<T> ReadContents()
    {
        int offset = this.PageNr * this.PageSize;
        int fetch = this.PageSize;
        string cmdText = "SELECT col1, col2, ..."
          + " FROM ... "
          + " WHERE ... "
          + " ORDER BY -- " 
          // this is a MUST there must be ORDER BY statement
          //-- the paging comes here
          + $" OFFSET {offset} ROWS"
          + $" FETCH NEXT {fetch} ROWS ONLY;";

        using (SqlCommand cmd = new SqlCommand("cmdText, conn))
        {
            using (var sqlDataReader = cmd.ExecuteQuery())
            {
                List<T> readItems = sqlDataReader...;
                // you know better than I how to use the SqlDataReader                    
                return readItems
            }
        }
    }
}

Fetch / Offset而不是Enumerable Skip / Take的想法来自stackoverflow上的Implement paging in SQL