winforms C # .NET-루프 (for, foreach 등…)를 사용하는 동안 내 코드의 성능을 향상시키는 방법 [닫힌]

Jan 29 2021

저는 대학 용 앱을 개발 중이며, 앱의 일부는 주간 수업 일정을 설정하는 것입니다.

내 매개 변수는 교실 번호, 요일 및 시간 슬롯입니다.

그래서 저는 다양한 교실을 가지고 있고 각 교실에는 숫자가 있습니다.

런타임에서 앱은 데이터베이스에있는 강의실 수에 따라 몇 개의 버튼을 생성하고 각 버튼에 강의실 번호를 설정합니다.

내가 원하는 것은 주어진 요일과 주어진 시간 슬롯에 특정 교실이 가득 찬 경우 각 교실 버튼에 "빨간색"BackColor를 표시하는 것입니다.

내가하고 싶은 일을 완수했고 내 코드는 오류없이 작동하지만 이제 유일한 문제는 성능입니다.

내 코드는 다음과 같습니다.

private OleDbConnection Connection = new OleDbConnection();


private void SomeMethod(string Day, string Time)
    {
        int MaxIndex = 0;
        string str1 = "select Max([Row Index]) from Table";       
      OleDbCommand Command1 = new OleDbCommand(str1, Connection);
        Connection.Open();
        if (Command1.ExecuteScalar() == DBNull.Value)
            MaxIndex = 1;

        else
            MaxIndex = Convert.ToInt32(Command1.ExecuteScalar());
        Connection.Close();

        for (int i = 0; i < MaxIndex; i++)
        {
            string str = "select [classroom Number] from Table where [Day] = @ParamDay and [Time] = @ParamTime and [Row Index] = @ParamIndex";

            OleDbCommand Command = new OleDbCommand(str, Connection);
            Command.Parameters.Add("@ParamDay", Day);
            Command.Parameters.Add("@ParamTime", Time);
            Command.Parameters.Add("@ParamIndex", i + 1);

            Connection.Open();
            OleDbDataReader reader = Command.ExecuteReader();

            if (reader.Read())
            {
                foreach (Button btn in ButtonsPanel.Controls)
                {
                    if (btn.Text == reader["classroom Number"].ToString())
                    {
                        btn.BackColor = Color.Red;
                    }

                }
                Connection.Close();
            }
        }


    }
    

따라서이 코드는 내가 가질 것으로 예상되는 행이 200 개 있으면 약 13 초가 걸립니다.

질문은 ...이 13 초가 최소 2-4 초로 줄어들도록 코드에 할 수있는 일이 있습니까?

정보 : 인터넷에서 많이 검색했지만 여기에서 내 문제에 대한 해결책을 찾을 수 없습니다.

답변

AntonínLejsek Jan 29 2021 at 10:22

for 사이클이 전혀 필요하지 않은 것 같습니다. 그리고 MaxIndex둘 중 하나. 시간에 대한 기록을 다운로드하고 버튼을 표시하십시오.

private void SomeMethod(string Day, string Time)
{
    HashSet<string> classNumbers = new HashSet<string>();

    string str = "select [classroom Number] from Table where [Day] = @ParamDay and [Time] = @ParamTime";
    using (OleDbCommand Command = new OleDbCommand(str, Connection))
    {
        Command.Parameters.Add("@ParamDay", Day);
        Command.Parameters.Add("@ParamTime", Time);                
        Connection.Open();
        using (OleDbDataReader reader = Command.ExecuteReader(CommandBehavior.CloseConnection))
        {
            while (reader.Read())
            {
                classNumbers.Add(reader["classroom Number"].ToString());
            }
        }
    }

    foreach (Button btn in ButtonsPanel.Controls)
    {
        if (classNumbers.Contains(btn.Text))
        {
            btn.BackColor = Color.Red;
        }
    }
}
GellioGao Jan 29 2021 at 09:37

개선하기 위해 변경할 수있는 두 가지 사항이 있습니다.

  1. 연결을 한 번만 열고 닫아 코드 실행 시간을 줄일 수 있습니다.
  2. 하나의 쿼리로 처리 할 모든 데이터를 가져옵니다.

아래 코드를 확인하십시오.

    private OleDbConnection Connection = new OleDbConnection();

    private void SomeMethod(string Day, string Time)
    {
        int MaxIndex = 0;
        string str1 = "select Max([Row Index]) from Table";       
        OleDbCommand Command1 = new OleDbCommand(str1, Connection);
        Connection.Open();
        if (Command1.ExecuteScalar() == DBNull.Value)
            MaxIndex = 1;
        else
            MaxIndex = Convert.ToInt32(Command1.ExecuteScalar());

        string str = "select [classroom Number] from Table where [Day] = @ParamDay and [Time] = @ParamTime and [Row Index] between 1 and @ParamIndex";

        OleDbCommand Command = new OleDbCommand(str, Connection);
        Command.Parameters.Add("@ParamDay", Day);
        Command.Parameters.Add("@ParamTime", Time);
        Command.Parameters.Add("@ParamIndex", MaxIndex);

        OleDbDataReader reader = Command.ExecuteReader();
        while (reader.Read())
        {
            foreach (Button btn in ButtonsPanel.Controls)
            {
                if (btn.Text == reader["classroom Number"].ToString())
                {
                    btn.BackColor = Color.Red;
                }
            }
        }

        Connection.Close();
    }
Hayden Jan 29 2021 at 10:28

내 의견에 따라 쿼리를 한 번만 실행하고 결과 집합을 반복하면됩니다. IO가 일반적으로 매우 느리기 때문에 이제 IO에 한 번만 액세스하므로 성능이 향상됩니다.

다음은 예입니다 (테스트되지 않음).

private void SomeMethod(string day, string time)
{
    // Using statement helps to dispose any resources once done with the connection
    // connectionString can be any string that opens your database
    using (OleDbConnection connection = new OleDbConnection(connectionString))
    {
        // The query has removed the notion of index, it will just get all the data for that day and time
        string query = "SELECT [classroom Number] FROM Table WHERE [Day] = @ParamDay AND [Time] = @ParamTime";

        // Since OleDbCommand inherits from IDisposable, use a using statement
        using (OleDbCommand command = new OleDbCommand(query, connection))
        {
            // Notice how we don't use index anymore
            command.Parameters.Add("@ParamDay", day);
            command.Parameters.Add("@ParamTime", time);

            // Open connection here, don't need to close connection
            connection.Open();

            // Since OleDbDataReader inherits from IDisposable, use a using statement
            using (OleDbDataReader reader = command.ExecuteReader())
            {
                // We're now looping through all the rows in the result set
                while (reader.Read())
                {
                    UpdateButtonColor(reader["classroom Number"].ToString());
                }
            }
        }
    }
}

private void UpdateButtonColor(string classroomNumber)
{
    foreach (Button btn in ButtonsPanel.Controls)
    {
        if (btn.Text == classroomNumber)
        {
            btn.BackColor = Color.Red;
        }
    }
}

최신 버전의 C #에서는 using명령문에 중괄호 (중첩 감소)가 필요하지 않습니다.

private void SomeMethod(string day, string time)
{
    string query = "SELECT [classroom Number] FROM Table WHERE [Day] = @ParamDay AND [Time] = @ParamTime";
    using OleDbConnection connection = new OleDbConnection(connectionString);
    using OleDbCommand command = new OleDbCommand(query, connection);

    command.Parameters.Add("@ParamDay", day);
    command.Parameters.Add("@ParamTime", time);

    connection.Open();

    using OleDbDataReader reader = command.ExecuteReader();
    
    while (reader.Read())
    {
        UpdateButtonColor(reader["classroom Number"].ToString());
    }
}

이에 대한 문서는 여기 에서 찾을 수 있습니다 .