2016-12-20 2 views
1

Я пытаюсь извлечь кусок данных chunk из таблицы MySQL.Как получить кусок данных chunk из таблицы?

У меня есть таблица, как показано ниже:

HistoryLogs = 10986119 

Теперь я хотел бы принести кусок по данным куска от MyQSL и передать его sqlbulk копию для обработки. Я решил размер партии как .

Например, если у меня есть записи 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; 
      } 
     } 

Поэтому я не понимаю, как создать запрос на разбиение на страницы, и не уверен, правильно ли я думаю.

ответ

2

Немного неизвестно, какую технику вы хотите использовать для получения данных из базы данных.

Из-за ключевого слова Linq я предполагаю, что вам нужен оператор Linq, который дает вам страницу элементов с заданным размером страницы.

Однако неизвестно, как вы хотите получить данные для страницы X. У вас есть IQueryable записей, которые вы хотите разделить на страницы (как и в Entity Framework - настоятельно рекомендуется), или вы хотите изменить ваш оператор SQL, чтобы он дал вам страницу X?

IQueryable метод

Предположим, вы хотите страниц записей типа T и у вас есть IQueryable<T>, чтобы получить все записи типа T.

IQueryable<T> allRecords = ...; 

Вы хотите разделить эту последовательность на страницы , Каждая страница имеет PageSize, PageNr и последовательность записей:

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/Офсетный вместо перечислимого Skip/Take пришла Implement paging in SQL на StackOverflow.

+0

Это действительно потрясающе. Большое спасибо за предоставление ответа, и я действительно ценю ваши усилия –

Смежные вопросы