winforms C # .NET - So verbessern Sie die Leistung meines Codes bei Verwendung von Schleifen (for, foreach usw.) [geschlossen]

Jan 29 2021

Ich entwickle eine App für Hochschulen. Ein Teil der App besteht darin, den wöchentlichen Stundenplan festzulegen.

Meine Parameter sind Klassenzimmernummer, Wochentag und Zeitfenster.

Ich habe also eine Reihe von Klassenzimmern, jedes Klassenzimmer hat eine Nummer.

In der Laufzeit generiert die App einige Schaltflächen basierend auf der Anzahl der Klassenzimmer in meiner Datenbank und legt die Klassennummern für jede Schaltfläche fest.

Was ich tun möchte, ist, jede Klassenzimmer-Schaltfläche mit "Roter" BackColor zu kennzeichnen, wenn dieses bestimmte Klassenzimmer am angegebenen Wochentag und im angegebenen Zeitfenster voll ist.

Ich habe erreicht, was ich tun wollte, und mein Code funktioniert fehlerfrei, aber mein einziges Problem ist jetzt die Leistung.

Hier ist mein Code:

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


    }
    

Dieser Code dauert also ungefähr 13 Sekunden, wenn ich 200 Zeilen habe, die ich erwartet habe.

Die Frage ist ... Kann ich irgendetwas mit meinem Code tun, damit sich diese 13 Sekunden auf mindestens 2-4 Sekunden reduzieren?

Zur Information: Ich habe viel im Internet gesucht, konnte hier aber keine Lösung für mein Problem finden.

Antworten

AntonínLejsek Jan 29 2021 at 10:22

Sie scheinen den for-Zyklus überhaupt nicht zu brauchen. Und das auch MaxIndexnicht. Laden Sie einfach die Datensätze für die Zeit- und Markierungsschaltflächen herunter.

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

Es gibt zwei Dinge, die Sie ändern können, um sie zu verbessern:

  1. Öffnen und schließen Sie die Verbindung nur einmal, wodurch sich die Code-Laufzeit verkürzen kann.
  2. Rufen Sie alle Daten, die Sie verarbeiten möchten, in einer Abfrage ab.

Überprüfen Sie den Code unten:

    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

Gemäß meinen Kommentaren müssen Sie die Abfrage nur einmal ausführen und die Ergebnismenge durchlaufen. Dies führt zu Leistungssteigerungen, da Sie jetzt nur noch einmal auf die E / A zugreifen, da die E / A normalerweise sehr langsam ist.

Hier ist ein Beispiel (noch nicht getestet):

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

Neuere Versionen von C # ermöglichen, dass für die usingAnweisung keine geschweiften Klammern erforderlich sind (wodurch die Verschachtelung verringert wird). Dies würde folgendermaßen aussehen:

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

Dokumentation hierzu finden Sie hier