3

データベースからリストに約 200 万行を読み込むプログラムがあります。各行は、地理座標などの情報を含む場所です。

リストにデータが追加されたら、foreach ループを使用して座標を取得し、kml ファイルを作成します。行数が多い場合、ループで OutOfMemoryException エラーが発生します (ただし、それ以外の場合は完全に機能します)。

プログラムが非常に大きなデータセットを処理できるように、これを処理する方法について何か提案はありますか? kml ライブラリは SharpKML です。

私はまだC#に慣れていないので、簡単に行ってください!

これはループです:

            using (SqlConnection conn = new SqlConnection(connstring))
        {
            conn.Open();
            SqlCommand cmd = new SqlCommand(select, conn);

            using (cmd)
            {
                SqlDataReader reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    double lat = reader.GetDouble(1);
                    double lon = reader.GetDouble(2);
                    string country = reader.GetString(3);
                    string county = reader.GetString(4);
                    double TIV = reader.GetDouble(5);
                    double cnpshare = reader.GetDouble(6);
                    double locshare = reader.GetDouble(7);

                    //Add results to list
                    results.Add(new data(lat, lon, country, county, TIV, cnpshare, locshare));
                }
                reader.Close();
            }
            conn.Close();
        }

            int count = results.Count();
            Console.WriteLine("number of rows in results = " + count.ToString());

            //This code segment generates the kml point plot

            Document doc = new Document();
            try
            {
                foreach (data l in results)
                {
                    Point point = new Point();
                    point.Coordinate = new Vector(l.lat, l.lon);

                    Placemark placemark = new Placemark();
                    placemark.Geometry = point;
                    placemark.Name = Convert.ToString(l.tiv);

                    doc.AddFeature(placemark);

                }
            }
            catch(OutOfMemoryException e)
            {
                throw e;
            }

これはリストで使用されるクラスです

        public class data
    {
        public double lat { get; set; }
        public double lon { get; set; }
        public string country { get; set; }
        public string county { get; set; }
        public double tiv { get; set; }
        public double cnpshare { get; set; }
        public double locshare { get; set; }

        public data(double lat, double lon, string country, string county, double tiv, double cnpshare,
            double locshare)
        {
            this.lat = lat;
            this.lon = lon;
            this.country = country;
            this.county = county;
            this.tiv = tiv;
            this.cnpshare = cnpshare;
            this.locshare = locshare;
        }

    }
4

4 に答える 4

5

書き込む前にすべてのデータを保存する必要があるのはなぜですか? 各行をリストに追加するのではなく、各行が読み取られるたびに処理し、その後は無視する必要があります。

たとえば、次のようにコードをまとめてみてください。

Document doc = new Document();
while (reader.Read())
{
    // read from db
    double lat = reader.GetDouble(1);
    double lon = reader.GetDouble(2);
    string country = reader.GetString(3);
    string county = reader.GetString(4);
    double TIV = reader.GetDouble(5);
    double cnpshare = reader.GetDouble(6);
    double locshare = reader.GetDouble(7);

    var currentData = new data(lat, lon, country, county, TIV, cnpshare, locshare));

    // write to file
    Point point = new Point();
    point.Coordinate = new Vector(currentData.lat, currentData.lon);

    Placemark placemark = new Placemark();
    placemark.Geometry = point;
    placemark.Name = Convert.ToString(currentData.tiv);

    doc.AddFeature(placemark);
}

Documentただし、これは賢明に実装されている場合にのみ機能します。

于 2012-06-12T16:36:21.913 に答える
2

オリバーは正しいです(私からの賛成票)。パフォーマンスに関しては、他のことを行うことができます。まず、使用しないフィールドに対してクエリを実行しないでください。次に、すべての変数宣言 (Oliver のコード) を while ステートメント (?) の前に移動します。最後に、SQL サーバーがすべてのレコードを収集して送り返すのを待つ代わりに、段階的に段階的に実行します。たとえば、レコードに UID があり、それらを取得する順序がこの UID である場合、ローカル C# 変数 "var lastID = 0" で開始し、select ステートメントを (フォーマット前に) "select top 1000 ..." のように変更します。 where UID > lastID" を実行し、何も得られないか、1000 レコード未満になるまでクエリを繰り返します。

于 2012-06-12T16:59:48.997 に答える
1

@drdigit、

クエリをループで実行することは避けます。1 つのクエリは、その時点で必要なだけのデータを常に返す必要があります。この場合、1000 行を返す 1000 個のクエリがあります。最初の1000行をすばやく表示する方が良いかもしれませんが、1つのクエリのみを実行する代わりに、ループで1000の高速なクエリを実行した方が高速になるかどうかはわかりません.多分私は間違っています....

この状況でそれが必要な場合、あなたのアプローチは遅延読み込みに適していると思います。

于 2012-06-12T17:17:50.143 に答える
1

データベースからのデータをリストに入力する際に​​大きな遅延がなく、リストにデータを入力する際の問題について言及していない場合は、すぐにポイントと目印オブジェクトを作成してみませんか。コードは以下です。

    var doc = new Document();

    using (SqlConnection conn = new SqlConnection(connstring))
    {
        conn.Open();
        SqlCommand cmd = new SqlCommand(select, conn);

        using (cmd)
        {
            var reader = cmd.ExecuteReader();
            while (reader.Read())
            {
                double lat = reader.GetDouble(1);
                double lon = reader.GetDouble(2);
                string country = reader.GetString(3);
                string county = reader.GetString(4);
                double TIV = reader.GetDouble(5);
                double cnpshare = reader.GetDouble(6);
                double locshare = reader.GetDouble(7);

                var point = new Point();
                point.Coordinate = new Vector(lat , lon );

                var placemark = new Placemark();
                placemark.Geometry = point;
                placemark.Name = Convert.ToString(TIV);

                doc.AddFeature(placemark);

            reader.Close();
        }
        conn.Close();
    }

メモリ内の非常に多くのデータを取得する正当な理由がない場合は、遅延読み込みアプローチを試してください。

于 2012-06-12T16:46:40.773 に答える