none
Помогите разобраться почему DataReader работает медленней RRS feed

  • Вопрос

  • Есть специфическая программа, с большим количеством часто (практически онлайн) подгружаемых данных.  Прочитав несколько умных книжек пришел к 3 методам загрузки данных в программу:

     

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using Npgsql;
    using NpgsqlTypes;
    
    namespace ProjecctDataSetSpeedTest
    {
     public partial class Form1 : Form
     {
      private const string TBKV_TABLE = "basa2.tbkv";
      private const string KV_ID_FIELD = "kv_id";
      private const string KV_NUMBER_FIELD = "kv_number";
      private const string HOUSE_ID_FIELD = "house_id";
      private const string PHONE_FIELD = "phone";
      private const string TECH_OBSLUG_FIELD = "tech_obslug";
      private const string OBSLUG_FIELD = "obslug";
      private const string ADRES_ID_BASA_FIELD = "adres_id_basa";
      private const string FIO_FIELD = "fio";
      private const string DYMOHOD_FIELD = "dymohod";
      private const string VENTILYATSIYA_FIELD = "ventilyatsiya";
      private const string DYMOHOD2_FIELD = "dymohod2";
      private const string VENTILYATSIYA2_FIELD = "ventilyatsiya2";
      private const string PRICHINA_DYM_VENT_KOMMENT_FIELD = "prichina_dym_vent_komment";
      private const string KOLVO_OUTPUT_FIELD = "kolvo_output"; 
      private const string SELECT = "SELECT kv_id, kv_number, house_id, phone, tech_obslug, obslug, adres_id_basa, fio, dymohod, ventilyatsiya, dymohod2, ventilyatsiya2, prichina_dym_vent_komment, kolvo_output FROM basa2.tbkv limit 1000";  
      private const string ConnectionString_Basa = "Server=172.21.123.34;Port=5432;User Id=postgres;Password=******;Database=BASA;Encoding=UNICODE;CommandTimeout=60;ConnectionLifeTime=0;Pooling=true;MaxPoolSize=200;MinPoolSize=0;";
    
      public Form1()
      {
       InitializeComponent();
      }
    
      private DataSet CreateDataSet()
      {
       DataSet ds = new DataSet();
       //Создание талицы
       DataTable dtKV = new DataTable(TBKV_TABLE);
       DataColumnCollection cols = dtKV.Columns;
       //Создание полей
       cols.Add(KV_ID_FIELD, typeof(System.Int32)).AllowDBNull = false;
       cols[KV_ID_FIELD].AutoIncrement = true;
       cols[KV_ID_FIELD].AutoIncrementSeed = -1;
       cols[KV_ID_FIELD].AutoIncrementStep = -1;
       cols.Add(KV_NUMBER_FIELD, typeof(System.String));
       cols.Add(HOUSE_ID_FIELD, typeof(System.Int32));
       cols.Add(PHONE_FIELD, typeof(System.String));
       cols.Add(TECH_OBSLUG_FIELD, typeof(System.Boolean));
       cols.Add(OBSLUG_FIELD, typeof(System.Boolean));
       cols.Add(ADRES_ID_BASA_FIELD, typeof(System.Int32));
       cols.Add(FIO_FIELD, typeof(System.String));
       cols.Add(DYMOHOD_FIELD, typeof(System.Boolean));
       cols.Add(VENTILYATSIYA_FIELD, typeof(System.Boolean));
       cols.Add(DYMOHOD2_FIELD, typeof(System.Int32));
       cols.Add(VENTILYATSIYA2_FIELD, typeof(System.Int32));
       cols.Add(PRICHINA_DYM_VENT_KOMMENT_FIELD, typeof(System.String));
       cols.Add(KOLVO_OUTPUT_FIELD, typeof(System.Int32));
       //Создание первичного ключа
       dtKV.PrimaryKey = new DataColumn[] { cols[KV_ID_FIELD] };
       ds.Tables.Add(dtKV);   
       return ds;
      }
    
      //стандартный DataSet
      private void LoadStandartDataSet()
      {
       DataSet ds = new DataSet();
       NpgsqlDataAdapter nda = new NpgsqlDataAdapter(SELECT, ConnectionString_Basa);
       nda.Fill(ds, TBKV_TABLE);
       dataGridView1.DataSource = ds.Tables[TBKV_TABLE];   
      }
      
      //с предварительным созданием таблицы
      private void LoadOptimaze1Dataset()
      {
       DataSet ds = new DataSet();
       ds = CreateDataSet();
       NpgsqlDataAdapter da = new NpgsqlDataAdapter(SELECT, Form1.ConnectionString_Basa);
       ds.Tables[TBKV_TABLE].BeginLoadData();
       da.Fill(ds, TBKV_TABLE);
       ds.Tables[TBKV_TABLE].EndLoadData();
       dataGridView1.DataSource = ds.Tables[TBKV_TABLE];   
      }
      //c DataReader
      private void LoadOptimaze2Dataset()
      {
       DataSet ds = new DataSet();
       ds = CreateDataSet();
       NpgsqlConnection conn = new NpgsqlConnection(ConnectionString_Basa);
       conn.Open();
       NpgsqlCommand command = new NpgsqlCommand(SELECT, conn);
    
       try
       {
        NpgsqlDataReader dr = command.ExecuteReader();
        Int32 KV_ID_COLUMN = dr.GetOrdinal(KV_ID_FIELD);
        Int32 KV_NUMBER_COLUMN = dr.GetOrdinal(KV_NUMBER_FIELD);
        Int32 HOUSE_ID_COLUMN = dr.GetOrdinal(HOUSE_ID_FIELD);
        Int32 PHONE_COLUMN = dr.GetOrdinal(PHONE_FIELD);
        Int32 TECH_OBSLUG_COLUMN = dr.GetOrdinal(TECH_OBSLUG_FIELD);
        Int32 OBSLUG_COLUMN = dr.GetOrdinal(OBSLUG_FIELD);
        Int32 ADRES_ID_BASA_COLUMN = dr.GetOrdinal(ADRES_ID_BASA_FIELD);
        Int32 FIO_COLUMN = dr.GetOrdinal(FIO_FIELD);
        Int32 DYMOHOD_COLUMN = dr.GetOrdinal(DYMOHOD_FIELD);
        Int32 VENTILYATSIYA_COLUMN = dr.GetOrdinal(VENTILYATSIYA_FIELD);
        Int32 DYMOHOD2_COLUMN = dr.GetOrdinal(DYMOHOD2_FIELD);
        Int32 VENTILYATSIYA2_COLUMN = dr.GetOrdinal(VENTILYATSIYA2_FIELD);
        Int32 PRICHINA_DYM_VENT_KOMMENT_COLUMN = dr.GetOrdinal(PRICHINA_DYM_VENT_KOMMENT_FIELD);
        Int32 KOLVO_OUTPUT_COLUMN = dr.GetOrdinal(KOLVO_OUTPUT_FIELD);
        while (dr.Read())
        {
         
         DataRow drow = ds.Tables[TBKV_TABLE].NewRow();
         drow[KV_ID_COLUMN] = dr.GetInt32(KV_ID_COLUMN);
         drow[KV_NUMBER_COLUMN] = dr.GetString(KV_NUMBER_COLUMN);
         drow[HOUSE_ID_COLUMN] = dr.GetInt32(HOUSE_ID_COLUMN);
         drow[PHONE_COLUMN] = dr.GetString(PHONE_COLUMN);
         drow[TECH_OBSLUG_COLUMN] = dr.GetBoolean(TECH_OBSLUG_COLUMN);
         drow[OBSLUG_COLUMN] = dr.GetBoolean(OBSLUG_COLUMN);
         drow[ADRES_ID_BASA_COLUMN] = dr.GetValue(ADRES_ID_BASA_COLUMN);
         drow[FIO_COLUMN] = dr.GetString(FIO_COLUMN);
         drow[DYMOHOD_COLUMN] = dr.GetBoolean(DYMOHOD_COLUMN);
         drow[VENTILYATSIYA_COLUMN] = dr.GetBoolean(VENTILYATSIYA_COLUMN);
         drow[DYMOHOD2_COLUMN] = dr.GetInt32(DYMOHOD2_COLUMN);
         drow[VENTILYATSIYA2_COLUMN] = dr.GetInt32(VENTILYATSIYA2_COLUMN);
         drow[PRICHINA_DYM_VENT_KOMMENT_COLUMN] = dr.GetString(PRICHINA_DYM_VENT_KOMMENT_COLUMN);
         drow[KOLVO_OUTPUT_COLUMN] = dr.GetInt32(KOLVO_OUTPUT_COLUMN);
         ds.Tables[TBKV_TABLE].Rows.Add(drow);
        }
        dataGridView1.DataSource = ds.Tables[TBKV_TABLE];
       }
    
       finally
       {
        conn.Close();
       }
      }
    
      private void button1_Click(object sender, EventArgs e)
      {
       DataSet ds = new DataSet();
       DateTime dt = new DateTime();
       listBox1.Items.Clear();
       System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
       System.Diagnostics.Stopwatch sw_all = new System.Diagnostics.Stopwatch();
       for (int i = 0; i < (Int32)numericUpDown1.Value; i++)
       {
        sw.Start();
        sw_all.Start();
        switch (comboBox1.SelectedIndex)
        {
         case 0: LoadStandartDataSet(); break;
         case 1: LoadOptimaze1Dataset(); break;
         case 2: LoadOptimaze2Dataset(); break;
         default:
          break;
        }
        sw.Stop();
        sw_all.Stop();
        TimeSpan ts;
        ts = sw.Elapsed;
        listBox1.Items.Add(ts.ToString());
        dataGridView1.DataSource = null;
        dataGridView1.Refresh();
        sw.Reset();
        ds.Clear();
       }
       TimeSpan ts_all;
       ts_all = sw_all.Elapsed;
       label3.Text = "Среднее время выполнения: " + ts_all.ToString();
      }
    
    
     }
    }
    

     

    Замерив результаты при 100 итерациях получилось:

    Стандартная загрузка нетипизированного DataSet - 4426 мс (среднее 43 мс, первая 392 мс)

    Загрузка с предварительным созданием программно таблицы - 4418 мс (среднее 39 мс, первая 385 мс)

    С использованием DataReader - 5401 мс (среднее 55, первая 393)

    Теоретически "c использованием DataReader" должно быть самым быстрым, в чем я ошибся подскажите пожалуйста. И еще почему первое значение в несколько раз медленней последующих?


    • Изменено alexfess 10 августа 2011 г. 7:40 ошибка в коде
    10 августа 2011 г. 7:36

Ответы

  •  while (dr.Read())
      {
      data.Add(new PersonData{
    				Id = Convert.ToInt32(dr[KV_ID_COLUMN]),
    				Number = Convert.ToString(dr[KV_NUMBER_COLUMN]),
    				HouseId = Convert.ToInt32(dr[HOUSE_ID_COLUMN]),
    				Phone = Convert.ToString(dr[PHONE_COLUMN]),
    				IsTechObslug = Convert.ToBoolean(dr[TECH_OBSLUG_COLUMN]),
    				IsObslug = Convert.ToBoolean(dr[OBSLUG_COLUMN]),
    				Fio = Convert.ToString(dr[FIO_COLUMN]),
    				IsDymohod = Convert.ToBoolean(dr[DYMOHOD_COLUMN]),
    				IsVentilation = Convert.ToBoolean(dr[VENTILYATSIYA_COLUMN]),
    				Dymohod2Id = Convert.ToInt32(dr[DYMOHOD2_COLUMN]),
    				Ventilation2Id =Convert.ToInt32(dr[VENTILYATSIYA2_COLUMN]),
    				ErrorReasonDescription = Convert.ToString(dr[PRICHINA_DYM_VENT_KOMMENT_COLUMN]),
    				CountOfOutputColumns = Convert.ToInt32(dr[KOLVO_OUTPUT_COLUMN])
    		});
      }
    

    я бы так писал. 

    Но мне кажется что перфоманс падает из-за того что ты каждый раз дергаешь запрос как Query команду.

     

     private const string SELECT = "SELECT kv_id, kv_number, house_id, phone, tech_obslug, obslug, adres_id_basa, fio, dymohod, ventilyatsiya, dymohod2, ventilyatsiya2, prichina_dym_vent_komment, kolvo_output FROM basa2.tbkv limit 1000"; 
    
    это лучше переписать как хранимую процедуру и дергать ее.
    Плюс строку подключения к базе данных надо хранить в файле конфигурации.
     private const string ConnectionString_Basa = "Server=172.21.123.34;Port=5432;User Id=postgres;Password=******;Database=BASA;Encoding=UNICODE;CommandTimeout=60;ConnectionLifeTime=0;Pooling=true;MaxPoolSize=200;MinPoolSize=0;";

    посмотри System.Configuration.ConfigurationManager это для win form приложений, и System.Web.Configuration.ConfigurationManager это для веб приложений.

     


    • Помечено в качестве ответа Abolmasov Dmitry 1 сентября 2011 г. 22:05
    12 августа 2011 г. 10:27

Все ответы

  • А попробуй так померить:

        private void LoadOptimaze2Dataset()
        {
          DataSet ds = new DataSet();
          ds = CreateDataSet();
          using (NpgsqlConnection conn = new NpgsqlConnection(ConnectionString_Basa))
          {
            conn.Open();
            NpgsqlCommand command = new NpgsqlCommand(SELECT, conn);
            NpgsqlDataReader dr = command.ExecuteReader();
            ds.Tables[TBKV_TABLE].Load(dr);
          }
          dataGridView1.DataSource = ds.Tables[TBKV_TABLE];
        }
    
    По поводу первой выборки: попробуй вынести открытие соединения за пределы измерений.

    10 августа 2011 г. 8:18
    Модератор
  • немного изменил код 

    DataSet ds = new DataSet();
    ds = CreateDataSet();
    if (conn.State == ConnectionState.Closed)
       conn.Open();
    NpgsqlCommand command = new NpgsqlCommand(SELECT, conn);
    NpgsqlDataReader dr = command.ExecuteReader();
    ds.Tables[TBKV_TABLE].Load(dr);
    dataGridView1.DataSource = ds.Tables[TBKV_TABLE];
    


    открываю соединение перед началом замера времени.

    Результат такой - 3979 мс (среднее 35-40 мс, первое 102 мс)

    10 августа 2011 г. 8:30
  • а схему таблицы я правильно заполняю? если честно думал разница будет ощутимей. 
    10 августа 2011 г. 8:40
  • Попробуй вынести создание DataSet'а и таблицы за пределы измерений.
    Попробуй померить скорость, не создавая структуры таблицы.
     
    10 августа 2011 г. 9:52
    Модератор
  • Вынес, изменилось совсем чуть чуть:

    Результат такой - 3884 мс (среднее 35-40 мс, первое 82 мс)

    10 августа 2011 г. 10:22
  • А explain analyze показывает какое время выполнения запроса?
     
     
    10 августа 2011 г. 10:46
    Модератор
  • вообще фигня какая то 140-150 мс. еще замерил отдельно загрузку данных и выгрузку оных в DataGridView. Получилось примерно соотношение 70% на 30%.  Меня в принципе это время устраивает, больше волнует какой из методов взять на вооружение - просто с созданием таблицы или еще и с DataReader

    P.S. при выполнении explain analyze подгружается табличка и показывается, а в программе на экран так ничего и не попадает. Если в  explain analyze лимит уменьшить до 100 он выполняется 22 мс, если до 10  - 12мс, если до 1 - 11 мс.

    10 августа 2011 г. 11:10
  • explain analyze нужно запускать на сервере. В PgAdmin'е подключись к серверу  и выполни

    explain analyze SELECT kv_id, kv_number, house_id, phone, tech_obslug, obslug, adres_id_basa, fio, dymohod, ventilyatsiya, dymohod2, ventilyatsiya2, prichina_dym_vent_komment, kolvo_output FROM basa2.tbkv limit 1000
    
    Он тебе покажет время выполнения запроса на сервере.

    10 августа 2011 г. 12:42
    Модератор
  • Никогда так не делал :) вот результат:

    Limit (cost=0.00..27.03 rows=1000 width=64) (actual time=0.024..9.225 rows=1000 loops=1)
    -> Seq Scan on tbkv (cost=0.00..2404.96 rows=88958 width=64) (actual time=0.017..4.875 rows=1000 loops=1)
    Total runtime: 11.525 ms
    10 августа 2011 г. 14:04
  •  //c DataReader
     
     private void LoadOptimaze2Dataset()
     {
      DataSet ds = new DataSet();
      ds = CreateDataSet();
      NpgsqlConnection conn = new NpgsqlConnection(ConnectionString_Basa);
      conn.Open();
      NpgsqlCommand command = new NpgsqlCommand(SELECT, conn);
    
      try
      {
      NpgsqlDataReader dr = command.ExecuteReader();
      Int32 KV_ID_COLUMN = dr.GetOrdinal(KV_ID_FIELD);
      Int32 KV_NUMBER_COLUMN = dr.GetOrdinal(KV_NUMBER_FIELD);
      Int32 HOUSE_ID_COLUMN = dr.GetOrdinal(HOUSE_ID_FIELD);
      Int32 PHONE_COLUMN = dr.GetOrdinal(PHONE_FIELD);
      Int32 TECH_OBSLUG_COLUMN = dr.GetOrdinal(TECH_OBSLUG_FIELD);
      Int32 OBSLUG_COLUMN = dr.GetOrdinal(OBSLUG_FIELD);
      Int32 ADRES_ID_BASA_COLUMN = dr.GetOrdinal(ADRES_ID_BASA_FIELD);
      Int32 FIO_COLUMN = dr.GetOrdinal(FIO_FIELD);
      Int32 DYMOHOD_COLUMN = dr.GetOrdinal(DYMOHOD_FIELD);
      Int32 VENTILYATSIYA_COLUMN = dr.GetOrdinal(VENTILYATSIYA_FIELD);
      Int32 DYMOHOD2_COLUMN = dr.GetOrdinal(DYMOHOD2_FIELD);
      Int32 VENTILYATSIYA2_COLUMN = dr.GetOrdinal(VENTILYATSIYA2_FIELD);
      Int32 PRICHINA_DYM_VENT_KOMMENT_COLUMN = dr.GetOrdinal(PRICHINA_DYM_VENT_KOMMENT_FIELD);
      Int32 KOLVO_OUTPUT_COLUMN = dr.GetOrdinal(KOLVO_OUTPUT_FIELD);
      while (dr.Read())
      {
       
       DataRow drow = ds.Tables[TBKV_TABLE].NewRow();
       drow[KV_ID_COLUMN] = dr.GetInt32(KV_ID_COLUMN);
       drow[KV_NUMBER_COLUMN] = dr.GetString(KV_NUMBER_COLUMN);
       drow[HOUSE_ID_COLUMN] = dr.GetInt32(HOUSE_ID_COLUMN);
       drow[PHONE_COLUMN] = dr.GetString(PHONE_COLUMN);
       drow[TECH_OBSLUG_COLUMN] = dr.GetBoolean(TECH_OBSLUG_COLUMN);
       drow[OBSLUG_COLUMN] = dr.GetBoolean(OBSLUG_COLUMN);
       drow[ADRES_ID_BASA_COLUMN] = dr.GetValue(ADRES_ID_BASA_COLUMN);
       drow[FIO_COLUMN] = dr.GetString(FIO_COLUMN);
       drow[DYMOHOD_COLUMN] = dr.GetBoolean(DYMOHOD_COLUMN);
       drow[VENTILYATSIYA_COLUMN] = dr.GetBoolean(VENTILYATSIYA_COLUMN);
       drow[DYMOHOD2_COLUMN] = dr.GetInt32(DYMOHOD2_COLUMN);
       drow[VENTILYATSIYA2_COLUMN] = dr.GetInt32(VENTILYATSIYA2_COLUMN);
       drow[PRICHINA_DYM_VENT_KOMMENT_COLUMN] = dr.GetString(PRICHINA_DYM_VENT_KOMMENT_COLUMN);
       drow[KOLVO_OUTPUT_COLUMN] = dr.GetInt32(KOLVO_OUTPUT_COLUMN);
       ds.Tables[TBKV_TABLE].Rows.Add(drow);
      }
      dataGridView1.DataSource = ds.Tables[TBKV_TABLE];
      }
    

    DataReader работает медленее потому как вы в цикле while создаете dataRow и заполняете его и в конце добавляете его в DataTable, это занимает значительную часть времени.

     

    Для улучшения производительности я бы рекомендовал написать класс для бизнесс объекта:

     public class PersonData
     {
            public int Id
    		{
    			get;
    			set;
    		}
    
    		public string Number
    		{
    			get;
    			set;
    		}
    
    		public int HouseId
    		{
    			get;
    			set;
    		}
    
    		public string Phone
    		{
    			get;
    			set;
    		}
    
    		public bool IsTechObslug
    		{
    			get;
    			set;
    		}
    
    		public bool IsObslug
    		{
    			get;
    			set;
    		}
    
    		public object AddressOfBaseId
    		{
    			get;
    			set;
    		}
    
    		public string Fio
    		{
    			get;
    			set;
    		}
    
    		public bool IsDymohod
    		{
    			get;
    			set;
    		}
    
    		public bool IsVentilation
    		{
    			get;
    			set;
    		}
    
    		public int DymohodId
    		{
    			get;
    			set;
    		}
    
    		public string VentilationId
    		{
    			get;
    			set;
    		}
    
    		public string ErrorReasonDescription
    		{
    			get;
    			set;
    		}
    
    		public int CountOfOutputColumns
    		{
    			get;
    			set;
    		}
     }
    

    и в цикле while заполнять List<PersonData>.

    12 августа 2011 г. 5:27
  • сегодня попробую, если проблем с привязкой к DataGridView не возникнет
    12 августа 2011 г. 6:19
  • Создал класс как ты и советовал:

     private void LoadOptimaze3DataSet()
        {
          NpgsqlConnection conn = new NpgsqlConnection(ConnectionString_Basa);
          if (conn.State == ConnectionState.Closed)
            conn.Open();
          NpgsqlCommand command = new NpgsqlCommand(SELECT, conn);
          NpgsqlDataReader dr = command.ExecuteReader();
          Int32 KV_ID_COLUMN = dr.GetOrdinal(KV_ID_FIELD);
          Int32 KV_NUMBER_COLUMN = dr.GetOrdinal(KV_NUMBER_FIELD);
          Int32 HOUSE_ID_COLUMN = dr.GetOrdinal(HOUSE_ID_FIELD);
          Int32 PHONE_COLUMN = dr.GetOrdinal(PHONE_FIELD);
          Int32 TECH_OBSLUG_COLUMN = dr.GetOrdinal(TECH_OBSLUG_FIELD);
          Int32 OBSLUG_COLUMN = dr.GetOrdinal(OBSLUG_FIELD);
          Int32 FIO_COLUMN = dr.GetOrdinal(FIO_FIELD);
          Int32 DYMOHOD_COLUMN = dr.GetOrdinal(DYMOHOD_FIELD);
          Int32 VENTILYATSIYA_COLUMN = dr.GetOrdinal(VENTILYATSIYA_FIELD);
          Int32 DYMOHOD2_COLUMN = dr.GetOrdinal(DYMOHOD2_FIELD);
          Int32 VENTILYATSIYA2_COLUMN = dr.GetOrdinal(VENTILYATSIYA2_FIELD);
          Int32 PRICHINA_DYM_VENT_KOMMENT_COLUMN = dr.GetOrdinal(PRICHINA_DYM_VENT_KOMMENT_FIELD);
          Int32 KOLVO_OUTPUT_COLUMN = dr.GetOrdinal(KOLVO_OUTPUT_FIELD);
          PersonData p_temp = new PersonData();
          while (dr.Read())
          {
            p_temp.Id = dr.GetInt32(KV_ID_COLUMN);
            p_temp.Number = dr.GetString(KV_NUMBER_COLUMN);
            p_temp.HouseId = dr.GetInt32(HOUSE_ID_COLUMN);
            p_temp.Phone = dr.GetString(PHONE_COLUMN);
            p_temp.IsTechObslug = dr.GetBoolean(TECH_OBSLUG_COLUMN);
            p_temp.IsObslug = dr.GetBoolean(OBSLUG_COLUMN);
            //p_temp.adre drow[ADRES_ID_BASA_COLUMN] = dr.GetValue(ADRES_ID_BASA_COLUMN);
            p_temp.Fio = dr.GetString(FIO_COLUMN);
            p_temp.IsDymohod = dr.GetBoolean(DYMOHOD_COLUMN);
            p_temp.IsVentilation = dr.GetBoolean(VENTILYATSIYA_COLUMN);
            p_temp.Dymohod2Id = dr.GetInt32(DYMOHOD2_COLUMN);
            p_temp.Ventilation2Id = dr.GetInt32(VENTILYATSIYA2_COLUMN);
            p_temp.ErrorReasonDescription = dr.GetString(PRICHINA_DYM_VENT_KOMMENT_COLUMN);
            p_temp.CountOfOutputColumns = dr.GetInt32(KOLVO_OUTPUT_COLUMN);
            data.Add(p_temp);
          }
          dataGridView1.DataSource = data;
          conn.Close();
        }
    

    Вот результат: 4645 мс, среднее 40-50, первое 232.

    Наверное опять при заполнении в чем то косяк. Скорее всего в этом:

    data.Add(p_temp);
    

    Но как по другому заполнять не знаю :( 

    12 августа 2011 г. 7:46
  • > программа, с большим количеством часто (практически онлайн) подгружаемых данных.

    подгружать данные можно в отдельном потоке.
    для вывода на экран: DataGridView в VirtualMode. http://www.gotdotnet.ru/forums/3/117572/554678/#post554678

    12 августа 2011 г. 8:21
  • это я для теста использовал лимит 1000, в реальной программе там всего 1-10 записей. Просто в окне программы 4 DataGridView и еще пачка Label, ComboBox привязанных к данным, т.к. клиентов много приходится часто все это обновлять, и соответственно критична скорость обновления с базы. Интерфейс сейчас потихоньку на WPF переписываю :)
    12 августа 2011 г. 8:25
  • Вот тут очень подробно расписывается про увеличение скорости работы с БД.
    12 августа 2011 г. 9:32
  • а заполнение объекта правильное, или можно как то по другому?
    12 августа 2011 г. 9:34
  •  while (dr.Read())
      {
      data.Add(new PersonData{
    				Id = Convert.ToInt32(dr[KV_ID_COLUMN]),
    				Number = Convert.ToString(dr[KV_NUMBER_COLUMN]),
    				HouseId = Convert.ToInt32(dr[HOUSE_ID_COLUMN]),
    				Phone = Convert.ToString(dr[PHONE_COLUMN]),
    				IsTechObslug = Convert.ToBoolean(dr[TECH_OBSLUG_COLUMN]),
    				IsObslug = Convert.ToBoolean(dr[OBSLUG_COLUMN]),
    				Fio = Convert.ToString(dr[FIO_COLUMN]),
    				IsDymohod = Convert.ToBoolean(dr[DYMOHOD_COLUMN]),
    				IsVentilation = Convert.ToBoolean(dr[VENTILYATSIYA_COLUMN]),
    				Dymohod2Id = Convert.ToInt32(dr[DYMOHOD2_COLUMN]),
    				Ventilation2Id =Convert.ToInt32(dr[VENTILYATSIYA2_COLUMN]),
    				ErrorReasonDescription = Convert.ToString(dr[PRICHINA_DYM_VENT_KOMMENT_COLUMN]),
    				CountOfOutputColumns = Convert.ToInt32(dr[KOLVO_OUTPUT_COLUMN])
    		});
      }
    

    я бы так писал. 

    Но мне кажется что перфоманс падает из-за того что ты каждый раз дергаешь запрос как Query команду.

     

     private const string SELECT = "SELECT kv_id, kv_number, house_id, phone, tech_obslug, obslug, adres_id_basa, fio, dymohod, ventilyatsiya, dymohod2, ventilyatsiya2, prichina_dym_vent_komment, kolvo_output FROM basa2.tbkv limit 1000"; 
    
    это лучше переписать как хранимую процедуру и дергать ее.
    Плюс строку подключения к базе данных надо хранить в файле конфигурации.
     private const string ConnectionString_Basa = "Server=172.21.123.34;Port=5432;User Id=postgres;Password=******;Database=BASA;Encoding=UNICODE;CommandTimeout=60;ConnectionLifeTime=0;Pooling=true;MaxPoolSize=200;MinPoolSize=0;";

    посмотри System.Configuration.ConfigurationManager это для win form приложений, и System.Web.Configuration.ConfigurationManager это для веб приложений.

     


    • Помечено в качестве ответа Abolmasov Dmitry 1 сентября 2011 г. 22:05
    12 августа 2011 г. 10:27
  • Сделал по твоему способу, получился вот такой код:

    while (dr.Read())
          {
            data.Add(new PersonData
            {
              Id = dr.GetInt32(KV_ID_COLUMN),
              Number = dr.GetString(KV_NUMBER_COLUMN),
              HouseId = dr.GetInt32(HOUSE_ID_COLUMN),
              Phone = dr.GetString(PHONE_COLUMN),
              IsTechObslug = dr.GetBoolean(TECH_OBSLUG_COLUMN),
              IsObslug = dr.GetBoolean(OBSLUG_COLUMN),
              //p_temp.adre drow[ADRES_ID_BASA_COLUMN] = dr.GetValue(ADRES_ID_BASA_COLUMN);
              Fio = dr.GetString(FIO_COLUMN),
              IsDymohod = dr.GetBoolean(DYMOHOD_COLUMN),
              IsVentilation = dr.GetBoolean(VENTILYATSIYA_COLUMN),
              Dymohod2Id = dr.GetInt32(DYMOHOD2_COLUMN),
              Ventilation2Id = dr.GetInt32(VENTILYATSIYA2_COLUMN),
              ErrorReasonDescription = dr.GetString(PRICHINA_DYM_VENT_KOMMENT_COLUMN),
              CountOfOutputColumns = dr.GetInt32(KOLVO_OUTPUT_COLUMN)
            });
            
          }
          dataGridView1.DataSource = data;
    


    Скорость выполнения изменилась значительно - 2886 мс, среднее 20-30 мс, первое 233 мс

    Сейчас сделаю с какой нить хранимкой, но в хранимой процедуре нельзя вернуть такую же кучу столбцов с разными названиями

    12 августа 2011 г. 10:44
  • Почему нельзя? Хранимая процедура может иметь несколько OUTPUT параметров. А можно просто также ей возвращать результаты SELECT.

    Можно как пример посмотреть (здесь одновременно и OUTPUT и SELECT) - ADO.NET: How to get Return Value of a Stored Procedure


    Для связи [mail]
    12 августа 2011 г. 13:51
  • Мой ответ был не корректен. Не все БД это умеют :-) Да и к тому же, для тестирования ладно можно использовать, мало ли что. Но для реального приложения все равно будут использоваться обычные Select`ы
    12 августа 2011 г. 13:54
  • Хорошо =) Если вас устраивает производительнось, то не забудьте отметить ответ Henadzi Sabaleuski, который помог ее добиться. Или будите продолжать копать дальше?


    Для связи [mail]
    12 августа 2011 г. 14:03
  • Даже если сделать представление (View). Работать будет быстрее чем обычный запрос. Но если хочешь добиться оптимальной скорости работы, то советую посмотреть как работать с курсорами в БД (если твоя база это позволит).
    13 августа 2011 г. 6:45
  • Не думал если честно. что от того делаешь запрос просто к таблице или через View - меняется скорость, обязательно завтра протестирую. По поводу курсоров, разве DataReader не работает по принципу "Пожарного шланга", т.е. это уже работа с курсорами. 

    14 августа 2011 г. 14:14
  • не совсем так... датаридер отличается от курсоров... но логику работы в MS залаживали похожую. а View должно быть быстрее, по крайней мере в оракле и в скл последних версий, особенно если к нему часто обращаться, на незначительном еоличестве операций, этого возможно не будет заметно.
    14 августа 2011 г. 19:25
  • Прежде чем браться за курсоры, нужно все-таки определить, какое место у тебя больше всего кушает.

    explain analyze говорит, что выборка 1000 записей делается примерно 11,525 ms, следовательно остальные потери на передаче данных и обработке на клиенте.

    Уходить в курсоры и хранимые процедуры, это значит оптимизировать, то что съедает около 30 процентов (в самом худшем случае).

     

    15 августа 2011 г. 5:11
    Модератор
  • Согласен, того что добились в принципе вполне достаточно. С передачей по факту особо ничего не сделаешь, клиент в 100Mb сети. Сервер в ней же. Другой кусок который занимает много времени, это прием данных из сети и упаковка их в DataSet или свой класс. И еще 1 кусок заполнение DataGridView и других компонентов, ну тут по моему мнению особо ничего не сделаешь, все рекомендованные при этом настройки я делал. Сегодня после обеда попробую еще View и отпишусь по результатам. И наверное можно будет уже закрывать тему.
    15 августа 2011 г. 5:32
  • > Другой кусок который занимает много времени, это прием данных из сети и упаковка их в DataSet или свой класс

    если в DataSet указать EnforceConstraints=false, то это по-идее ускорит загрузку.

    P.S.
    если данные надо масимально быстро вывести на экран, то DataSet лучше вообще не использовать.
    а в DataGridView выводить только строки, которые в данный момент видныа на экране.

    15 августа 2011 г. 5:47
  • Использую это:
     ds.Tables[TBKV_TABLE].BeginLoadData();
     da.Fill(ds, TBKV_TABLE);
     ds.Tables[TBKV_TABLE].EndLoadData();
    По идеи примерно одно и тоже. К тому же создаю таблицу в программе сам и без Primary Key и прочих ограничений. Чисто форматы данных и все, так быстрее грузится. У меня на форме примерно 2-3 DataGridView (с небольшим кол-вом строк, все гарантированно умещаются на экран), шутки 3 ComboBox и десятка 3 Label. Буду наверное использовать классы как советовал Henadzi Sabaleuski

    15 августа 2011 г. 5:57