0

オブジェクトの一部である double のこの大きな配列があります。これらのオブジェクトはデータベースに格納されます。各フィールドを内部に持つテーブルを作成しました。この大きな double の配列をテーブルに格納する方法を見つけようとして立ち往生しています。配列のサイズはオブジェクトごとに可変であり、非常に大きいため、各列にこれらの double を含む別のテーブルを必ずしも作成できるとは限りません。したがって、データベースをセットアップするときに、テーブルを調べて何千ものフロートを追加すると、時間がかかります。

この double の配列を列に格納するにはどうすればよいですか?

4

4 に答える 4

3

識別列を増やすだけです。

  • 配列 ID
  • ArrayIndexX
  • ArrayIndexY (2 次元配列で必要な場合)
  • 価値

これにより、格納する必要があるデータのサイズにもかかわらず、追加の列を追加する必要のない 1 つのテーブルを作成できます。

列が適切にインデックス化されていると仮定すると、数千または数百万のレコードを保存することは、実際にはそれほど大したことではありません。

幸運を

于 2013-07-18T19:25:16.903 に答える
1

double の配列をモデルの別のプロパティにパックし、シリアル化されたデータを保存します。最速のパッキング アルゴリズムはhttp://nuget.org/packages/protobuf-netです。配列に約 450 万以上を格納する運用アプリで次を使用します。

これを最小限に抑えたことに注意してください。おそらく、Pack/Unpack 呼び出しを最適化して、すべてのプロパティ アクセスで発生しないようにすることをお勧めします。

Surface以下の例では、サンプルの配列を含むスキャンの配列を含むデータベースに保存します。double[] のプロパティにも同じ概念が適用されます。

[ProtoBuf.ProtoContract]
public class Sample
{
    public Sample()
    {
    }

    [ProtoBuf.ProtoMember(2)]
    public double Max { get; set; }

    [ProtoBuf.ProtoMember(3)]
    public double Mean { get; set; }

    [ProtoBuf.ProtoMember(1)]
    public double Min { get; set; }
}

[ProtoBuf.ProtoContract]
public class Scan
{
    public Scan()
    {
    }

    [ProtoBuf.ProtoMember(1)]
    public Sample[] Samples { get; set; }
}

public class Surface
{
    public Surface()
    {
    }

    public int Id { get; set; }

    public byte[] ScanData { get; set; }

    [NotMapped]
    public Scan[] Scans
    {
        get
        {
            return this.Unpack();
        }
        set
        {
            this.ScanData = this.Pack(value);
        }
    }

    private byte[] Pack(Scan[] value)
    {
        using (var stream = new MemoryStream())
        {
            ProtoBuf.Serializer.Serialize(stream, value);
            return stream.ToArray();
        }
    }

    private Scan[] Unpack()
    {
        using (var stream = new MemoryStream(this.ScanData))
        {
            return ProtoBuf.Serializer.Deserialize<Scan[]>(stream);
        }
    }
}
于 2013-07-18T20:44:47.557 に答える
1

最初に決定する必要があるのは、データ管理の観点から配列がアトミックかどうかです。

  • はいの場合(つまり、データベース内にある個々の配列要素を検索、読み取り、または書き込む必要がない場合)、単純にシリアル化して BLOB に書き込みます。必要に応じて圧縮することもできます。
  • そうでない場合(つまり、個々の要素にアクセスする必要がある場合)、「メイン」テーブルと N:1 の関係にある別のテーブルを作成します。例えば:

    ここに画像の説明を入力

于 2013-07-19T00:46:25.453 に答える
1

別のテーブルを使用する必要があります

データに対してハッキーな書式設定を行うべきではありません。そうすると、何をしようとしているのかがわかりにくくなり、機能レベルで何をしようとしているのか混乱してしまいます。

別のテーブルが必要な理由

リンク テーブルが必要な理由は、BLOB に保持できるデータの最大量を超える可能性がある場合に BLOB にデータを配置したとしても、保持するデータの量がわからないためです。 .

コード

吸収ポイント用に別のオブジェクトを作成し、それをディクショナリに保存したいのですが、このようにして、頻繁に発生するデフォルトのケースがある場合 (ポイントで何も見つからない場合など)、全体を保存する必要はありません。もの。

コレクションを表すために別のクラスを作成するのが最善ですが、誰かがクラスを再利用し、何が起こっているのかわからない場合、不要なデータを追加することはありません。

public class SpectroscopyObject
{
     private FrequencyAbsorptionPointCollection _freqs = new FrequencyAbsorptionPointCollection ();
     public FrequencyAbsorptionPointCollection FrequecyAbsorption {get{ return _freqs;}}
     public int Id {get;set;}

     //other stuff...
} 

public struct Point 
{
    public int X {get;set;}
    public int Y {get;set;}

    public Point ( int x , int y ) 
    {
            X = x;
            Y = y;
    }
}

public class FrequencyAbsorptionPoint
{
    public double Frequency { get; set; }
    public Point Location { get; set; }
}

public class FrequencyAbsorptionPointCollection : IEnumerable<FrequencyAbsorptionPoint>
{
    private readonly Dictionary<int , Dictionary<int , FrequencyAbsorptionPoint>> _points = new Dictionary<int , Dictionary<int , FrequencyAbsorptionPoint>> ( ); 

    int _xLeftMargin , _xRightMargin , _yTopMargin , _yBottomMargin;
    public FrequencyAbsorptionPointCollection (int xLeftBound,int xRightBound,int yTopBound,int yBottomBound)
    {
        _xLeftMargin = xLeftBound;
        _xRightMargin = xRightBound;
        _yTopMargin = yTopBound;
        _yBottomMargin = yBottomBound;
    }

    private bool XisSane(int testX)
    {
        return testX>_xLeftMargin&&testX<_xRightMargin;
    }


    private bool YisSane(int testY)
    {
        return testY>_yBottomMargin&&testY<_yTopMargin;
    }

    private bool PointIsSane(Point pointToTest)
    {
        return XisSane(pointToTest.X)&&YisSane(pointToTest.Y);
    }

    private const double DEFAULT_ABSORB_VALUE= 0.0;
    private bool IsDefaultAbsorptionFrequency(double frequency)
    {
        return frequency.Equals(DEFAULT_ABSORB_VALUE);
    }

    //I am assuming default to be 0

    public FrequencyAbsorptionPointCollection 
        (int xLeftBound,
         int xRightBound,
         int yTopBound,
         int yBottomBound,
         IEnumerable<FrequencyAbsorptionPoint> collection )
        :this(xLeftBound,xRightBound,yTopBound,yBottomBound)
    {
        AddCollection ( collection );
    }

    public void AddCollection ( IEnumerable<FrequencyAbsorptionPoint> collection ) 
    {
        foreach ( var point in collection )
        {
            Dictionary<int , FrequencyAbsorptionPoint> _current = null;
            if ( !_points.ContainsKey ( point.Location.X ) )
            {
                _current = new Dictionary<int , FrequencyAbsorptionPoint> ( );
                _points.Add ( point.Location.X , _current );
            }
            else
                _current = _points [ point.Location.X ];

            if ( _current.ContainsKey ( point.Location.Y ) )
                _current [ point.Location.Y ] = point;
             else
                _current.Add ( point.Location.Y , point );
        }
    }

    public FrequencyAbsorptionPoint this [ int x , int y ] 
    {
         get 
         {
            if ( XisSane ( x ) && YisSane ( y ) )
            {
                if ( _points.ContainsKey ( x ) && _points [ x ].ContainsKey ( y ) )
                    return _points [ x ] [ y ];
                else
                    return new FrequencyAbsorptionPoint
                {
                    Id = 0 ,
                    Location = new Point ( x , y ) ,
                    Frequency = DEFAULT_ABSORB_VALUE
                };
            }
            throw new IndexOutOfRangeException (
                string.Format( "Selection ({0},{1}) is out of range" , x , y ));
        }
        set 
        {
            if ( XisSane ( x ) && YisSane ( y ) ) 
            {
                if ( !IsDefaultAbsorptionFrequency ( value.Frequency ) ) 
                {
                    Dictionary<int,FrequencyAbsorptionPoint> current = null;
                    if ( _points.ContainsKey ( x ) )
                        current = _points [ x ];
                    else
                    {
                        current = new Dictionary<int,FrequencyAbsorptionPoint>();
                        _points.Add ( x , current );
                    }

                    if ( current.ContainsKey ( y ) )
                        current [ y ] = value;
                    else
                    {
                        current.Add ( y , value );
                    }
                }
            }
        }
    }

    public FrequencyAbsorptionPoint this [ Point p ] 
    {
        get 
        {
            return this [ p.X , p.Y ];
        }
        set 
        {
            this [ p.X , p.Y ] = value;
        }
    }

    public IEnumerator<FrequencyAbsorptionPoint> GetEnumerator ( )
    {
        foreach ( var i in _points.Keys )
            foreach ( var j in _points [ i ].Keys )
                yield return _points [ i ] [ j ];
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ( )
    {
        return GetEnumerator ( );
    }
}

さて、SQLコード

CREATE TABLE SpectroscopyObject ( Id INT PRIMARY KEY NOT NULL, --other stuff )

CREATE TABLE FrequencyAbsorptionInfo ( Id INT PRIMARY KEY NOT NULL IDENTITY, XCoord INT NOT NULL, YCoord INT NOT NULL, AbsorptionInfo NUMERIC(5,5) NOT NULL, SpectroscopyObjectId INT NOT NULL FOREIGN KEY REFERENCES SpectroscopyObject(Id) )

あとは、ポイントを保存し、関連するオブジェクトをオブジェクトの ID で参照するだけです。読み取りたい場合は、次のようになります。

string commandStringSObjs = 
@"
SELECT Id, ..other attributes... FROM SpectroscopyObject
";
string commandStringCoords = 
@"
SELECT XCoord,YCoord,AbsorptionInfo 
WHERE SpectroscopyObjectId = @Id
";

var streoscopicObjs = new List<SpectroscopyObject>();
using(var connection = new SqlConnection(CONNECTION_STRING))
{
    using(var cmd = connection.CreateCommand())
    {
        cmd.CommandText = commandStringSObjs;
        connection.Open();
        using(var rdr = cmd.ExecuteReader())
        {
            while(rdr.Read())
            {

                streoscopicObjs.Add(new SpectroscopyObject
                {
                    Id = Convert.ToInt32(rdr["Id"])
                    //populate your other stuff
                }
            }
        }
    }
    //to read the absorption info
    foreach(var obj in streoscopicObjs)
    {
        var current = obj.FrequecyAbsorption;
        using(var cmd = connection.CreateCommand())
        { 
            cmd.CommandText = commandStringCoords;
            cmd.Parameters.Add(
                new SqlParameter("Id",DbType.Int){ Value = obj.Id});
            using(var rdr = cmd.ExecuteReader())
            {
                while(rdr.Read())
                {
                    var x = Convert.ToInt32(rdr["XCoord"]);
                    var y = Convert.ToInt32(rdr["YCoord"]);
                    var freq = Convert.ToDouble(rdr["AbsorptionInfo"]);

                    current[x][y] = new FrequencyAbsorptionPoint
                    {
                        Location = new Point(x,y),
                        Frequency = freq
                    };
                }
            }
        }
    }

    //do some stuff
    ...
   // assuming you update 
    string updatefreq = 
@"


INSERT INTO FrequencyAbsorptionInfo(XCoord,YCoord,
                   AbsorptionInfo,SpectroscopyObjectId )
VALUES(@xvalue,@yvalue,@freq,@Id) ";
    //other point already

    //to write the absorption info
    foreach(var obj in streoscopicObjs)
    {
        using(var cmd = connection.CreateCommand())
        {
            cmd.CommandText = 
@"
DELETE FrequencyAbsoptionInfo 
WHERE  SpectroscopyObjectId =@Id
";
            cmd.Parameters.Add(new SqlParameter("Id",DbType.Int){ Value = obj.Id});
            cmd.ExecuteNonQuery();
        }
        var current = obj.FrequecyAbsorption;
        foreach(var freq in current)
        {
            using(var cmd = connection.CreateCommand())
            { 
                cmd.CommandText = updatefreq ;
                cmd.Parameters.AddRange(new[]
                {
                    new SqlParameter("Id",DbType.Int){ Value = obj.Id},
                    new SqlParameter("XCoords",DbType.Int){ Value = freq.Location.X},
                    new SqlParameter("YCoords",DbType.Int){ Value = freq.Location.Y},
                    new SqlParameter("freq",DbType.Int){ Value = freq.Frequency },
                });
                cmd.ExecuteNonQuery();
            }
        }
    }
}
于 2013-07-18T21:26:42.017 に答える