Есть ли более быстрый способ заполнить набор результатов из запроса к базе данных? - PullRequest
3 голосов
/ 08 июля 2011

У меня есть следующий код, который запрашивает базу данных и заполняет таблицу данных.

private DataTable Run(string sql)
    {
        var conn = new OdbcConnection();

        string connString = "[myConnString];";

        conn.ConnectionString = connString;
         conn.Open();

        var da = new OdbcDataAdapter {SelectCommand = conn.CreateCommand()};
        da.SelectCommand.CommandText = sql;
        var dt = new DataTable();
        da.Fill(dt);
        da.Dispose();
        conn.Close();

        return dt;
    }

Я только что запустил на нем профилировщик, и он показывает, что на эту строку уходит очень много времени:

 da.Fill(dt);

Запрос возвращает только около 1000 строк. Вот подробности профиля того, что происходит внутри .net по этому вызову:

enter image description here

Учитывая, что я выполняю запрос, преобразую его в таблицу данных и затем преобразую эту таблицу в список объектов, есть ли что-нибудь ниже, что я могу сделать, чтобы оптимизировать это (каким-то образом преобразовать адаптер данных в список объектов напрямую ??). Я в основном ищу обходной путь для этого узкого места производительности в этом коде?

Ответы [ 4 ]

2 голосов
/ 08 июля 2011

Я думаю, что ответ на ваш запрос выполняется быстро. Код не может быть намного быстрее, но оптимизация запроса может иметь огромное значение. Можете ли вы использовать SQL Profiler и проверить выполнение необработанного SQL-запроса?

Например, добавление индексов базы данных или возврат меньшего числа столбцов. Задержка сети также может вызвать медлительность. База данных находится в той же локальной сети, в которой выполняется код?

1 голос
/ 08 июля 2011

Я бы рекомендовал использовать OdbcDataReader вместе с функцией Transform. Должно работать что-то вроде следующего:

public class OdbcQuery
{
    OdbcCommand Command { get; set; }

    public OdbcQuery(OdbcConnection connection, string cmdText)
    {
        Command = new OdbcCommand(cmdText, connection); 
    }

    public List<T> Transform<T>(Func<OdbcDataReader, T> transformFunction)
    {
        Command.Connection.Open();

        OdbcDataReader reader = Command.ExecuteReader(CommandBehavior.Default);

        List<T> tList = new List<T>();

        while (reader.Read())
        {
            tList.Add(transformFunction(reader));
        }

        Command.Connection.Close();

        return tList; 
    }
}

Вот пример функции преобразования, которая создаст экземпляр типа T для каждой строки в запросе. В данном случае это просто объект Foo,

public class Foo
{
    public Foo() { }

    public string FooString { get; set; }
    public int FooInt { get; set; }
}

class Program
{
    public static List<Foo> GetFooList(string connectionString, string cmdText)
    {
        OdbcQuery query = new OdbcQuery(new OdbcConnection(connectionString), cmdText);

        List<Foo> fooList = query.Transform(
            rdr =>
            {
                Foo foo = new Foo();

                foo.FooInt = rdr.GetInt32(0);
                foo.FooString = rdr.GetString(1); 

                return foo; 
            });

        return fooList; 
    }

Это должно работать хорошо, потому что ваши доменные объекты создаются при первом обходе результатов базы данных, не требуется второй или третий этапы перевода.

0 голосов
/ 08 июля 2011

В дополнение к DataReader вы можете проверить, правильно ли разработан ваш запрос.

Возможно, вы можете оптимизировать его или разделить событие на несколько параллельных действий

0 голосов
/ 08 июля 2011

Если вы ищете скорость, не используйте наборы данных / адаптеры данных, это старая технология, не созданная для скорости. Используйте устройство чтения данных, как предложил Шон.

...