Почему запуск второго считывателя с первым считывателем read () выполняется быстрее, чем запуск его на собственном считывателе? - PullRequest
3 голосов
/ 26 марта 2012

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

public List<HBPData> LoadData()
    {

        loadConnect(); //<-- get's the Pervasive/Access string from a text file
        List<HBPData> listofhbpdata1 = new List<HBPData>();
        List<HBPData> listofhbpdata2 = new List<HBPData>();

            PsqlConnection myConnection = new PsqlConnection();
            myConnection.ConnectionString = PervasiveString;
            myConnection.Open();
            PsqlCommand myCommand = new PsqlCommand("Select NUMBER, CUST_NAME, PO_NO, REQD_DATE, PO_NO, CUST_PO_NO, ORD_DATE, STATUS FROM SALES_ORDER_HEADER WHERE ORD_DATE > 20120220 Order By ORD_DATE desc", myConnection);
            PsqlDataReader myreader = null;
            myreader = myCommand.ExecuteReader();

            while (myreader.Read())
            {
                HBPData DataEntity = new HBPData();
                DataEntity.NUMBER = (myreader["NUMBER"].ToString());
                DataEntity.CUST_NO = (myreader["CUST_NAME"].ToString()).Replace("'","");
                DataEntity.PO_NO = (myreader["PO_NO"].ToString());
                DataEntity.RequiredDateTime = (myreader["REQD_DATE"].ToString());
                DataEntity.Tag = (myreader["PO_NO"].ToString());
                DataEntity.Shape = (myreader["CUST_PO_NO"].ToString());
                DataEntity.ExpectedCompletion = myreader["ORD_DATE"].ToString().Substring(0, 4) + "/" + myreader["ORD_DATE"].ToString().Substring(4, 2) + "/" + myreader["ORD_DATE"].ToString().Substring(6, 2);
                DataEntity.MostRecentStatus = (myreader["STATUS"].ToString());
                listofhbpdata1.Add(DataEntity);
            }

            PsqlCommand myCommand1 = new PsqlCommand("Select NUMBER, RECNO, CODE, ORDD_DESCRIPTION, BVORDQTY FROM SALES_ORDER_DETAIL WHERE BVRVADDDATE > 20120220 AND (PROD_CODE = \'MET\' OR PROD_CODE = \'MDT\') Order By NUMBER desc", myConnection);
            PsqlDataReader myreader1 = null;
            myreader1 = myCommand1.ExecuteReader();

            while (myreader.Read()) 
            {
                HBPData DataEntity = new HBPData();
                DataEntity.NUMBER = (myreader1["NUMBER"].ToString());
                DataEntity.RECNO = (myreader1["RECNO"].ToString());
                DataEntity.CODE = (myreader1["CODE"].ToString());
                DataEntity.DESCRIPTION = (myreader1["ORDD_DESCRIPTION"].ToString());
                DataEntity.Quantity = (myreader1["BVORDQTY"].ToString());
                listofhbpdata2.Add(DataEntity);
            }

            myConnection.Close();
            myreader1.Close();
            myreader.Close();






            System.Data.OleDb.OleDbConnection myAccessConnection = new System.Data.OleDb.OleDbConnection();

            myAccessConnection.ConnectionString = AccessString;
            myAccessConnection.Open();
            System.Data.OleDb.OleDbCommand myAccessCommand3 = new System.Data.OleDb.OleDbCommand("delete from AllOrders", myAccessConnection);
            myAccessCommand3.ExecuteNonQuery();

            for (int i = 0; i < listofhbpdata2.Count(); ++i)
            {
                System.Data.OleDb.OleDbCommand myAccessCommand2 = new System.Data.OleDb.OleDbCommand("" +
                    "Insert into AllOrders VALUES('" +
                      listofhbpdata2[i].NUMBER + "'" + ",'" + listofhbpdata2[i].RECNO.ToString() + "'" +
                    ",'" + listofhbpdata2[i].CODE + "','" + listofhbpdata2[i].DESCRIPTION.Replace("\'", "F") + "'" +
                    ",'" + listofhbpdata2[i].Quantity + "')", myAccessConnection);
                myAccessCommand2.ExecuteNonQuery();
            }

            myAccessConnection.Close();

        return listofhbpdata1;
    }

Теперь ,. Если вы посмотрите внимательно, я опечатал 2-го читателя, он должен читать пока (myreader1.read ()) ... я случайно положил myreader.read ()

К моему удивлению, положив myreader.read (), я успешно запустился ... это то, что взорвал мой разум, ... я изменил его на "myreader1.read ()" и время выполнения кода было почти в два раза ......, во всяком случае, проверяя базу данных, все данные были там .....

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

но тогда откуда все данные?

В Sales_Order_Header значительно меньше полей, чем в Sales_Order_Detail. Если он выполняет чтение для первого, разве он не должен заканчиваться в конце таблицы заголовков, а затем останавливаться? так почему все данные там?

В любом случае время выполнения этого кода относительно медленное, у кого-нибудь есть предложения по улучшению моего кода?

Edit: просто чтобы показать, что 2-й читатель не на самом деле возвращает false: Debugger

как видите, отладчик вышел из считывателя

Ответы [ 3 ]

4 голосов
/ 28 марта 2012

Вы уверены, что получаете правильные данные при втором вызове myreader? Что-то выглядит не так: ваш цикл по myreader, который должен получать данные из вашего первого оператора SELECT, но ваш внутренний код ссылается на myreader1.

Так что странная вещь здесь не в том, что вторая итерация должна быть быстрее первой: она в том, что вторая итерация возвращает вам ожидаемые вами данные.
Итак, вопрос: вы уверены, что во втором цикле:

  • вы получаете ожидаемое количество итераций для всех записей, которые вы ожидаете от этого второго оператора SELECT, скажем, 5000 (в отличие от числа записей из первого оператора, скажем, 1000).

  • вы на самом деле получаете данные для каждой записи во втором выражении SELECT, а не только для одной и той же верхней записи каждый раз.

Что касается второй части вашего вопроса, как улучшить скорость передачи данных, я бы порекомендовал следующее:

  • Добавление данных посредством выполнения отдельных операторов INSERT будет медленным.
    Посмотрите на этот вопрос для некоторых очень быстрых альтернатив:
    Запись большого количества записей (массовая вставка) для доступа в .NET / C #

  • Если вы много работаете с базой данных Access, не открывайте и не закрывайте подключение к нему. Причину, по которой это может сильно повлиять на производительность, см. Где находится пул соединений OLE DB? .
    Я обычно создаю таблицу, которую я называю Dummy, с одной записью в ней (неважно, что это), а затем открываю на этой таблице программу чтения данных, которую я держу открытой до тех пор, пока не закрою приложение. Это гарантирует, что файл блокировки базы данных сохраняется и не создается / удаляется каждый раз, когда я выполняю какую-либо операцию с базой данных. Вы будете удивлены влиянием, которое это оказывает на производительность, если вы выполняете много операций с базой данных.

1 голос
/ 06 апреля 2012

Не знаю почему, но, думаю, напишу ответ на свой вопрос.

Хотя у меня нет хорошего ответа на вопрос, почему второй читатель работает успешно (без потери данных), у меня есть несколько способов заставить этот код работать быстрее, который не был предложен

First Off ~

 while (myreader.Read()) 
        {
            HBPData DataEntity = new HBPData();
            DataEntity.NUMBER = (myreader1["NUMBER"].ToString());
            DataEntity.RECNO = (myreader1["RECNO"].ToString());
            DataEntity.CODE = (myreader1["CODE"].ToString());
            DataEntity.DESCRIPTION = (myreader1["ORDD_DESCRIPTION"].ToString());
            DataEntity.Quantity = (myreader1["BVORDQTY"].ToString());
            listofhbpdata2.Add(DataEntity);
        }

        myConnection.Close();
        myreader1.Close();
        myreader.Close();






        System.Data.OleDb.OleDbConnection myAccessConnection = new System.Data.OleDb.OleDbConnection();

        myAccessConnection.ConnectionString = AccessString;
        myAccessConnection.Open();
        System.Data.OleDb.OleDbCommand myAccessCommand3 = new System.Data.OleDb.OleDbCommand("delete from AllOrders", myAccessConnection);
        myAccessCommand3.ExecuteNonQuery();

        for (int i = 0; i < listofhbpdata2.Count(); ++i)
        {
            System.Data.OleDb.OleDbCommand myAccessCommand2 = new System.Data.OleDb.OleDbCommand("" +
                "Insert into AllOrders VALUES('" +
                  listofhbpdata2[i].NUMBER + "'" + ",'" + listofhbpdata2[i].RECNO.ToString() + "'" +
                ",'" + listofhbpdata2[i].CODE + "','" + listofhbpdata2[i].DESCRIPTION.Replace("\'", "F") + "'" +
                ",'" + listofhbpdata2[i].Quantity + "')", myAccessConnection);
            myAccessCommand2.ExecuteNonQuery();
        }

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

  • Я должен добавить в базу данных внутри ридера, а не создавать цикл for, который просматривает созданный мной список, который больше ни для чего не используется

  • Я очищаю таблицу и заполняю ее теми же данными + дополнительными данными, когда я должен проверить, существует ли то, что я вставляю, уже существует, а затем вставлять только те строки, которые в данный момент не существуют

Я заменил этот код следующим :

while (myreader1.Read())
                    {
   System.Data.OleDb.OleDbCommand myAccessCommand2 = new System.Data.OleDb.OleDbCommand(
   "INSERT INTO AllOrders(OrderNumber,RecordNumber,Code, Description, Quantity) " +
   "SELECT TOP 1 '" + (myreader1["NUMBER"].ToString()) + "'" + ",'" + myreader1["RECNO"].ToString() + "'" +
   ",'" + (myreader1["CODE"].ToString()) + "','" + (myreader1["ORDD_DESCRIPTION"].ToString()).Replace("\'", "F") + "'" +
   ",'" + (myreader1["BVORDQTY"].ToString()) + "'" +
   " from AllOrders " +
   "WHERE NOT EXISTS(SELECT TOP 1 OrderNumber FROM AllOrders Where OrderNumber = '" + myreader1["NUMBER"].ToString() +"')", myAccessConnection);
                        myAccessCommand2.ExecuteNonQuery();

                    }

Теперь

Хотя запуск myreader.read, казалось, шел быстрее, я заменил его на myreader1 на тот случай, если он делает что-то плохое, что я не могу найти

Теперь он работает намного быстрее. Я не удосужился использовать DAO, как предложено в Запись большого количества записей (массовая вставка) в Access в .NET / C #

Потому что я уже использую system.data.OleDb

1 голос
/ 26 марта 2012

Можете ли вы дать нам строки, которые работают медленнее?

Попробуйте использовать блоки для работы с объектами IDisposable, такими как соединения с БД. Таким образом, вы будете в безопасности при наличии исключений. И вам не нужно будет явно указывать вызов Close ().

В цикле For добавлено много строк. Вместо этого попробуйте StringBuilder.

...