父子表的SQL策略
我可以使用一些帮助来确定从SQL数据库中检索父子对象的最佳(最高性能/易维护)策略。父子表的SQL策略
我继承了这段代码,而且我已经有了相对较短的截止日期,我希望尽可能少做基础性更改。我有足够的时间在下一个螺旋上实现nhibernate或其他ORM,我现在不能这样做。我以最少的修改时间在最短的时间内寻找最好的事情。
扭曲的是,有不同的儿童类型(实现一个普通的儿童界面)。
例如,
家长:VehicleFleet(包含车队名称,经理姓名,车辆列表)
儿童:IVehicle(包括制造商,型号,位置等)
但是,可能有多个车辆类型 - 例如汽车,厢式车,摩托车 - 各具有不同的属性/列。有一个独立的汽车,面包车和摩托车。可能有也可能没有VehicleBase表,其中包含适用于任何车辆的列。
返回多个VehicleFleet对象的最佳策略是什么,每个对象都有相关的Vehicle子对象?
这里有一对夫妇的战略我已经试过(伪代码提交) -
假设:
所有的getXXXX功能使用DataReader场景
方法1落后:简单&慢 - 这是做的最糟糕的方式,原因很明显
IEnumerable<Fleet> GetFleetsAndVehicles() {
foreach (var fleet in myFleetDao.GetAllFleets()) {
foreach (var vehicleTypeDao in myVehicleTypeDaos)
fleet.Vehicles.Add (vehicleTypeDao.GetVehicles (fleet.Id);
yield return fleet;
}
yield break;
}
方法2:预取儿童
IEnumerable<Fleet> GetFleetsAndVehicles() {
var allVehicles = (from vtd in myVehicleTypeDaos
from v in vtd.GetAllVehicles()
select v).ToLookup (v => v.FleetId);
foreach (var fleet in myFleetDao.GetAllFleets())
{
fleet.Vehicles = allVehicles[fleet.Id].ToList();
yield return fleet;
}
yield break;
}
方法3:预取儿童,儿童附加异步地
IEnumerable<Fleet> GetFleetsAndVehicles() {
foreach (var fleet in new AsyncGetter.GetFleetsAndVehicles())
yield return fleet;
yield break;
}
class AsyncGetter
{
// left out instance variables, Auto/Manual Reset Events, locking, etc. for brevity
IEnumerable<Fleet> GetFleetsAndVehicles()
{
StartAsyncStuff();
while (myUnconsumedFleets.Count > 0)
{
yield return myUnconsumedFleets.Remove (0);
WaitUntilMoreFleetsAreAdded();
}
yield break;
}
void StartAsyncStuff()
{
myAllVehicles = <same as method 2>
foreach (var fleet in myFleetDao.GetAllFleets())
{
AttachVehiclesAsync (fleet);
}
}
void AttachVehiclesAsync (Fleet f)
{
// assume using ThreadPool.QueueUserWorkItem right now
WaitForAllVehiclesToLoad();
f.Vehicles = myAllVehicles[f.Id].ToList();
myUnconsumedFleets.Add (f);
}
}
方法4:交错的父/子查询
IEnumerable<Fleet> GetFleetsAndVehicles() {
var allVehicles = from vtd in myVehicleTypeDaos
from v in vtd.GetAllVehicles()
orderby v.FleetId
select v;
var allVehiclesEnumerator = allVehicles.GetEnumerator();
foreach (var fleet in myFleetDao.GetAllFleets())
{
fleet.Vehicles = GetAllChildVehiclesAndMaintainEnumeratorPosition (allVehiclesEnumerator, fleet);
yield return fleet;
}
}
到目前为止,使用一些测试数据,我看到那个方法3是最高性能的(快于下一个最佳速度27%),而方法1是最差的(比方法1慢4倍)。
所以,如果你有建议,我很乐意听到他们!
由于没有提供有用的答案来解决手头问题,所以我需要说:I thought we had left the 'DIY data access layers' behind these days。当然,可能还有一些用例确实需要自定义数据读取器。尽管如此,将继承层次从数据库映射到对象模型通常不是其中之一。
有大量的ORM可用于解决这个问题。它被称为“Table per Type继承映射”。任何体面的ORM都支持这一点,并允许您热切地获取父母/子女关系。
如果表现真的是一个问题(是吗?),那么通过切换到“单表继承”策略(一个表中的所有类型,带有鉴别器列),您可能会获得最多的收益。
实体框架和NHibernate都支持单表和每表类型。 Linq 2 SQL(好吧,也许不是完整的ORM)只支持单表继承;正如@Albin Sunnanbo所说,如果您可以更改数据库模式,那么它可能是一个选项。还有很多其他的ORM值得研究。
在那里,它离开我的胸部;-),希望它有帮助。
这是一个完全可以接受的答案......但不是现在。我继承了一个项目,而且我已经有了相对较短的截止日期,我希望尽可能少做基础性的改变。我有足够的时间在下一个螺旋上实现nhibernate,我现在不能这样做。 我正在寻找最短的时间做最好的事情,以最少的修改。 – PhilChuang 2010-08-29 06:31:23
如果您首先获得所有需要选择的车队的所有车辆,并且获得该结果填充车队对象,那么我认为这将是最快的。
现在你确定已经解决了,哪一个最好?
如果您可以*选择单个表继承模型,而不是在LINQ2SQL中内置支持,请参阅http://msdn.microsoft.com/en-us/library/bb399352.aspx和http:// msdn。 microsoft.com/en-us/library/bb386919.aspx – 2010-08-28 07:14:01