winforms C # .NET - วิธีการปรับปรุงประสิทธิภาพของรหัสของฉันในขณะที่ใช้ลูป (สำหรับ foreach ฯลฯ ... ) [ปิด]

Jan 29 2021

ฉันกำลังพัฒนาแอพสำหรับวิทยาลัยส่วนหนึ่งของแอพคือการกำหนดตารางเรียนรายสัปดาห์

พารามิเตอร์ของฉันคือหมายเลข Classroom วันในสัปดาห์และช่วงเวลา

ดังนั้นฉันจึงมีห้องเรียนที่หลากหลายแต่ละห้องเรียนมีจำนวน

ใน Run-Time แอปจะสร้างปุ่มบางปุ่มตามจำนวนห้องเรียนที่ฉันมีในฐานข้อมูลของฉันและกำหนดหมายเลขห้องเรียนในแต่ละปุ่ม

สิ่งที่ฉันต้องการทำคือติดป้ายกำกับปุ่ม Classroom แต่ละปุ่มด้วย 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();
            }
        }


    }
    

ดังนั้นรหัสนี้จะใช้เวลาประมาณ 13 วินาทีถ้าฉันมี 200 แถวซึ่งฉันคาดว่าจะมี

คำถามคือ ... มีอะไรที่ฉันสามารถทำได้กับรหัสของฉันเพื่อให้ 13 วินาทีเหล่านี้ลดลงเหลืออย่างน้อย 2-4 วินาที?

สำหรับข้อมูล: ฉันได้ค้นหาข้อมูลมากมายบนอินเทอร์เน็ต แต่ไม่พบวิธีแก้ปัญหาของฉันที่นี่

คำตอบ

AntonínLejsek Jan 29 2021 at 10:22

ดูเหมือนคุณจะไม่ต้องการวงจรเลย และ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());
    }
}

เอกสารสำหรับสิ่งนี้สามารถพบได้ที่นี่