SqlDataReader gebruiken om lijst <T> in c # te vullen

Ik heb een klas zoals hieronder,

class Student
{
    public string Name {get; set;}
    public string Surname {get; set;}
    public int Age {get; set;}
    public string Address {get; set;}
}

En ik heb een MySql-tabel met 50.000 records. De structuur van de tabel is zoals hieronder,

ID        NAME       SURNAME        AGE          ADDRESS
1         Joe        Philip         20           Moscow
2         Misha      Johny          25           London
...

En ik heb een C# -code,

List students = new List();
string sql = "SELECT name,surname,age,address FROM Students";
command.CommandText = sql;
MySqlDataReader reader = command.ExecuteReader();
while(reader.Read())
{
    Student st = new Student();
    st.Name = reader["Name"].ToString();
    st.Surname = reader["Surname"].ToString();
    st.Age = Convert.ToInt32(reader["Age"].ToString());
    st.Address = reader["Address"].ToString();
    students.Add(st);
}

Maar het werkt erg langzaam. Welke methode adviseert u om deze code sneller te laten werken?

BIJWERKEN:

Wanneer ik deze code gebruik,

DataTable dt = new DataTable();
adapter.Fill(dt);

Het werkt erg goed en snelheid is heel normaal. Maar wat is het probleem dat ik probeer met mijn eigen lessen?

1
als ik hiervoor de dataset gebruik, zullen al deze gegevens in de memmory staan. Dus wat is het verschil als ik mijn eigen klas wil gebruiken?
toegevoegd de auteur namco, de bron
Zie mijn antwoord; je krijgt waarschijnlijk betere antwoorden als je ons vertelt wat je gaat doen met deze studentengegevens.
toegevoegd de auteur Jacob, de bron
Ons grotere punt is dat je niet noodzakelijk alle records uit de database hoeft te laden. Als u slechts een subset van de gegevens nodig heeft, kunt u uw zoekopdracht beperken met een where -clausule.
toegevoegd de auteur Jacob, de bron
Uit nieuwsgierigheid, waarom moet je de hele databasetabel helemaal in het geheugen lezen ? Het is het algemene idee van databases dat ze mogelijk veel meer gegevens kunnen opslaan dan ze in het geheugen kunnen verwerken en dat we het gegevensrecord op recordniveau moeten verwerken.
toegevoegd de auteur Vlad, de bron
Dit is zo snel als het waarschijnlijk krijgt, er is hier geen duidelijke verbetering of overzicht - heb je al deze records in het geheugen nodig?
toegevoegd de auteur BrokenGlass, de bron
Die code compileert niet. U wijst een string toe aan een int -eigenschap (leeftijd).
toegevoegd de auteur Klaus Byskov Pedersen, de bron
Natuurlijk is het langzaam. Lees geen 50k-records in één keer in het geheugen!
toegevoegd de auteur Gabe Moothart, de bron

2 antwoord

Als de code langzaam loopt, is de grootste oorzaak dat er 50.000 records zijn. Wat heb je precies nodig met 50.000 Student -objecten? Als u een manier kunt vinden om uw probleem op te lossen zonder al deze records te lezen en al deze objecten te maken, heeft u snellere code.

Bijwerken

Het gebruik van je eigen klas is prima. Meestal gaat het langzaam, dit komt omdat je code I/O gebonden is (je besteedt het grootste deel van je tijd aan het wachten op I/O). Om al die I/O te vermijden, kunt u de hoeveelheid gegevens die u ophaalt, verminderen (bijvoorbeeld door irrelevante kolommen of rijen uit uw gegevens te verwijderen) of door uw verwerking in de database uit te voeren via een complexere query of opgeslagen procedure.

Update 2

Om uw vervolgvraag te beantwoorden (waarom het maken van een lijst met objecten langzamer gaat dan het ophalen van een DataSet ), zou ik verwachten dat het lezen van de volledige query als een DataSet alleen zou zijn iets sneller dan het maken van een object. Ik ben niet bekend met hoe de MySQL .NET-bibliotheek is geïmplementeerd. Het is voor mij verrassend dat de twee methoden een groot verschil in snelheid zouden hebben. Misschien doet MySqlDataReader iets doms, zoals het gebruik van een interne DataSet . Als de uitvoering tussen de twee drastisch anders is, is het waarschijnlijk iets dat de auteur van die bibliotheek moet oplossen.

Update 3

Dit antwoord voor MySqlDataAdapter of MySqlDataReader voor bulkoverdracht? heeft een goed advies; het instellen van de BatchSize van de lezer kan nuttig zijn. Als de batchgrootte te klein is voor de lezer, zou dat het minder efficiënt maken met een groot aantal records zoals het uwe.

5
toegevoegd
ik schrijf examen controle programma. ik zal deze en andere gegevens gebruiken die ik hier niet liet zien voor het bepalen van punten van studenten. Ik kan DataSet hier gebruiken in plaats van studentenklasse. Maar ik gebruik liever mijn eigen klas. Er is geen probleem met RAM. Probleem alleen bij het invullen van lijst met gegevens. het werkt erg langzaam.
toegevoegd de auteur namco, de bron
Zonder de details te kennen van wat voor soort verwerking u aan het doen bent op de gegevens, kunnen we niet veel meer hulp bieden. Snellere code is code die minder doet, dus probeer een manier te vinden om uw code minder te laten doen (bijvoorbeeld om sommige bewerkingen naar de database te verplaatsen). Zie mijn update.
toegevoegd de auteur Jacob, de bron
toegevoegd de auteur Jacob, de bron

Het gebruik van de index of record in plaats van coulmname maakt de uitvoering een beetje beter gebruik

st.Name = reader[0].ToString();
instead of
st.Name = reader["Name"].ToString();

and 
st.Name = reader[0].ToString();
instead of 
st.Name = reader["surname"].ToString();
1
toegevoegd
Merk ook op dat de indexering van de snaren een goede hoofdlettergevoeligheid moet hebben, anders zal het vreselijk traag zijn. MySQL ADO.NET-implementatie is in dit geval raar. En het is alleen voor MySQL ADO, elke andere connector die ik heb getest werkte prima.
toegevoegd de auteur nawfal, de bron