winforms C # .NET - Cách cải thiện hiệu suất của mã của tôi trong khi sử dụng các vòng lặp (for, foreach, v.v.) [đã đóng]

Jan 29 2021

Tôi đang phát triển một ứng dụng dành cho các trường đại học, một phần của ứng dụng là đặt lịch học hàng tuần.

Các thông số của tôi là Số lớp học, Ngày trong tuần và Khoảng thời gian.

Vì vậy, tôi có một loạt các phòng học, mỗi phòng học có một số.

trong Run-Time, ứng dụng tạo một số nút dựa trên số lượng phòng học tôi có trên cơ sở dữ liệu của mình và đặt số lớp học trên mỗi Nút.

Điều tôi muốn làm là Gắn nhãn mỗi nút Lớp học bằng Màu nền "Đỏ" nếu lớp học đó đã kín chỗ trong Ngày trong tuần nhất định và Khoảng thời gian nhất định.

Tôi đã hoàn thành những gì tôi muốn làm và mã của tôi hoạt động không có lỗi, nhưng vấn đề duy nhất của tôi bây giờ là hiệu suất.

Đây là Mã của tôi:

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();
            }
        }


    }
    

vì vậy mã này mất khoảng 13 giây nếu tôi có 200 hàng mà tôi mong đợi.

Câu hỏi đặt ra là ... Tôi có thể làm gì với mã của mình để 13 giây này giảm xuống ít nhất 2-4 giây không?

Để biết thông tin: Tôi đã tìm kiếm rất nhiều trên internet, nhưng không thể tìm thấy giải pháp cho vấn đề của tôi ở đây.

Trả lời

AntonínLejsek Jan 29 2021 at 10:22

Bạn dường như không cần chu kỳ for cả. Và một MaxIndextrong hai. Chỉ cần tải xuống các bản ghi cho các nút thời gian và đánh dấu.

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

Có hai điều bạn có thể thay đổi để cải thiện:

  1. Chỉ mở và đóng kết nối một lần có thể giảm thời gian chạy mã.
  2. Tìm nạp tất cả dữ liệu bạn muốn xử lý trong một truy vấn.

Kiểm tra mã bên dưới:

    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

Theo nhận xét của tôi, bạn chỉ cần thực hiện truy vấn một lần và lặp qua tập kết quả. Điều này sẽ làm tăng hiệu suất vì bây giờ bạn chỉ truy cập IO một lần, vì IO thường rất chậm.

Đây là một ví dụ (chưa thử nghiệm):

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ác phiên bản mới hơn của C # cho phép usingcâu lệnh không yêu cầu dấu ngoặc nhọn (điều này làm giảm việc lồng vào nhau), giống như sau:

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());
    }
}

Tài liệu cho việc này có thể được tìm thấy ở đây