我有这么大的双打数组,它是一个对象的一部分。这些对象将存储在数据库中。我创建了一个包含每个字段的表。我一直在试图弄清楚如何在表格中存储这么多双打。我不一定能在每列中使用这些双精度来制作另一个表,因为数组大小每个对象都是可变的,而且它们非常大。因此,在设置我的数据库时,遍历表并添加数千个浮点数将非常耗时。
如何将这个双精度数组存储到一列中?
我有这么大的双打数组,它是一个对象的一部分。这些对象将存储在数据库中。我创建了一个包含每个字段的表。我一直在试图弄清楚如何在表格中存储这么多双打。我不一定能在每列中使用这些双精度来制作另一个表,因为数组大小每个对象都是可变的,而且它们非常大。因此,在设置我的数据库时,遍历表并添加数千个浮点数将非常耗时。
如何将这个双精度数组存储到一列中?
我只会有更多的识别列。
这将允许您拥有一个不需要添加其他列的表,尽管您需要存储的数据大小。
假设列被正确索引,存储数千/或数百万条记录真的不是什么大不了的事。
祝你好运
您需要确定的第一件事是从数据管理的角度来看数组是否是原子的:
如果否(即您确实需要访问各个元素),则创建一个单独的表,该表与“主”表具有 N:1 关系。例如:
将 double 数组打包到模型上的不同属性中并保存序列化数据。最快的打包算法是http://nuget.org/packages/protobuf-net。我在一个生产应用程序中使用以下内容,该应用程序在数组中存储了大约 450 万个以上。
请注意,我将其剥离到最低限度,您可能希望优化 Pack/Unpack 调用,以便它们不会在每个属性访问时发生。
在下面的示例中,我们保存Surface
到数据库中,其中包含一个 Scans 数组,其中包含一个样本数组。相同的概念适用于 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);
}
}
}
您不应该尝试对您的数据进行 hacky 格式化操作,这会使您更难以分辨您正在尝试做什么,并使您在功能级别上尝试做的事情变得混乱
你需要一个链接表的原因是因为你不知道你将持有多少数据,即使你把它放在一个 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();
}
}
}
}