Выбор миллиона записей из SQL Server - PullRequest
2 голосов
/ 11 февраля 2012

Нам нужно проиндексировать (в ASP.NET) все наши записи, хранящиеся в таблице SQL Server.Эта таблица содержит около 2M записей с текстовыми (nvarchar) данными в каждой строке.

Можно ли получить все записи за один раз, когда нам нужно их проиндексировать (для поиска)?Какой еще вариант (я хочу избежать разбивки на страницы)?

Примечание : я не отображаю эти записи, мне просто нужно, чтобы все они были выполнены за один раз, чтобы я мог их проиндексироватьфоновая нить.

Нужно ли устанавливать длительные тайм-ауты для моего запроса?Если да, то каков наиболее эффективный способ установки более длительного времени ожидания, если я выполняю запрос со страницы ASP.NET?

Ответы [ 5 ]

1 голос
/ 11 февраля 2012

Если бы мне нужно что-то подобное, просто подумав об этом со стороны базы данных, я бы, вероятно, экспортировал это в файл. Тогда этот файл может быть перемещен довольно легко. Перемещение больших массивов данных - огромная боль для всех участников. Вы можете использовать SSIS, sqlcmd или даже bcp в пакетной команде, чтобы сделать это.

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

0 голосов
/ 11 февраля 2012

Обработка ваших записей партиями. У вас будут две основные проблемы. (1) Вам необходимо проиндексировать все существующие записи. (2) вы хотите обновить индекс с записями, которые были добавлены, обновлены или удалены. Может показаться, что eaiser просто отбрасывает индекс и воссоздает его, но по возможности его следует избегать Ниже приведен пример обработки [Production].[TransactionHistory] из базы данных AdventureWorks2008R2 в пакетах по 10 000 записей. Он не загружает все записи в память. Вывод на мой локальный компьютер выдает Processed 113443 records in 00:00:00.2282294. Очевидно, что это не учитывает удаленный компьютер и время обработки каждой записи.

class Program
{
    private static string ConnectionString
    {
        get { return ConfigurationManager.ConnectionStrings["db"].ConnectionString; }
    }

    static void Main(string[] args)
    {
        int recordCount = 0;
        int lastId = -1;
        bool done = false;

        Stopwatch timer = Stopwatch.StartNew();

        do
        {
            done = true;

            IEnumerable<TransactionHistory> transactionDataRecords = GetTransactions(lastId, 10000);
            foreach (TransactionHistory transactionHistory in transactionDataRecords)
            {
                lastId = transactionHistory.TransactionId;
                done = false;
                recordCount++;
            }
        } while (!done);

        timer.Stop();

        Console.WriteLine("Processed {0} records in {1}", recordCount, timer.Elapsed);
    }

    /// Get a new open connection
    private static SqlConnection GetOpenConnection()
    {
        SqlConnection connection = new SqlConnection(ConnectionString);
        connection.Open();
        return connection;
    }

    private static IEnumerable<TransactionHistory> GetTransactions(int lastTransactionId, int count)
    {
        const string sql = "SELECT TOP(@count) [TransactionID],[TransactionDate],[TransactionType] FROM [Production].[TransactionHistory] WHERE [TransactionID] > @LastTransactionId ORDER BY [TransactionID]";

        return GetData<TransactionHistory>((connection) =>
                                               {
                                                   SqlCommand command = new SqlCommand(sql, connection);
                                                   command.Parameters.AddWithValue("@count", count);
                                                   command.Parameters.AddWithValue("@LastTransactionId", lastTransactionId);
                                                   return command;
                                               }, DataRecordToTransactionHistory);
    }

    // funtion to convert a data record to the TransactionHistory object
    private static TransactionHistory DataRecordToTransactionHistory(IDataRecord record)
    {
        TransactionHistory transactionHistory = new TransactionHistory();
        transactionHistory.TransactionId = record.GetInt32(0);
        transactionHistory.TransactionDate = record.GetDateTime(1);
        transactionHistory.TransactionType = record.GetString(2);

        return transactionHistory;
    }

    private static IEnumerable<T> GetData<T>(Func<SqlConnection, SqlCommand> commandBuilder, Func<IDataRecord, T> dataFunc)
    {
        using (SqlConnection connection = GetOpenConnection())
        {
            using (SqlCommand command = commandBuilder(connection))
            {
                using (IDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        T record = dataFunc(reader);
                        yield return record;
                    }
                }
            }
        }
    }
}

public class TransactionHistory
{
    public int TransactionId { get; set; }
    public DateTime TransactionDate { get; set; }
    public string TransactionType { get; set; }
}
0 голосов
/ 11 февраля 2012

Что вы описываете в Extract Transform Load (ETL). Есть 2 варианта, о которых я знаю:

  1. SSIS, которая является частью сервера sql
  2. Rhino.ETL

Я предпочитаю Rhino.Etl, так как он полностью написан на C #, вы можете создавать скрипты в Boo, и гораздо проще тестировать и составлять процессы ETL. А библиотека построена для обработки больших наборов данных, поэтому встроено управление памятью.

Последнее замечание: хотя asp.net может быть точкой входа для запуска процесса индексации, я не буду запускать этот процесс в asp.net, так как это может занять минуты или часы в зависимости от количества записей и обработки.

Вместо этого asp.net будет точкой входа для запуска фоновой задачи для обработки записей. В идеале, полностью независимый от asp.net, поэтому вы можете избежать проблем с таймаутом или отключением.

0 голосов
/ 11 февраля 2012

Можно ли получать все записи за один раз, когда нам нужно их проиндексировать (для поиска)?Какой еще вариант (я хочу избежать разбивки на страницы)?

Проблема управления памятью / проблема с производительностью

Вы можете столкнуться с исключением из-за недостатка памяти в случаевы приносите 2 миллиона записей. Поскольку вы будете хранить все эти записи в DataSet, а память набора данных будет в ОЗУ.


Нужно ли устанавливать длительные тайм-ауты для моего запроса?Если да, то каков наиболее эффективный способ установки более длительных тайм-аутов, если я выполняю запрос со страницы ASP.NET?

using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand())
{
   cmd.CommandTimeout = 0;
}

Предложение

  1. Лучше отфильтровать запись с уровня базы данных ...
  2. Получить все записи из базы данных и сохранить их в файле.Доступ к этому файлу для любых промежуточных операций.
0 голосов
/ 11 февраля 2012

Я не думаю, что страница - хорошее место для этого, независимо Должен быть другой процесс или программа, которая делает это. Может быть, что-то вроде http://incubator.apache.org/lucene.net/ вам поможет?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...