序言(你可以跳过这个,这只是我的理由)
我创建了一个使用 sqlite 作为其数据库后端的应用程序,并且该模式在一般应用程序使用期间工作(和执行)非常好。
现在我正在尝试为它构建一个报告系统,并且我已经构建了一个 excel xll,它从一个未命名的 DSN 创建查询表。因此,我只能在 sql 中完成所有报告(即我不能以编程方式执行任何操作)。这对除了一个查询之外的所有内容都非常有效......
/// 跳过这里....
我的数据库包含一个特征列表,其中包含一个 id、距离和一个指示该特征是否为标记的指示符。id 不一定与距离的顺序相同(id 为 10 的要素可能有距离 100,而 id 为 11 的要素可能有距离 90)。
所以这个项目基本上看起来像:
Feature { int id, int distance, bool is_marker }
我想做的是找到下一个和上一个特征也是标记。
/// 编辑
我的第一次尝试使用:
select
* /* I want all the data from this feature */
(select MAX(f2.distance) - f1.distance
from feature as f2
where f2.is_marker && f2.distance < f1.distance) /* and the distance to the previous marker */
from feature as f2
第二次尝试(这一次有效,对于 100,000 个功能来说,WAAAY 的时间太长了,大约需要 9 天......):
select
*, /* I want all the data from this feature */
(select f1.distance - MAX(f2.distance)
from feature as f2
where f2.distance AND f2.distance< f1.distance) /* and the distance to the previous marker */
from feature as f1
这个查询确实返回了我想要的,并且对小型数据库执行得很好,但我也必须支持更大的数据库。
(有些数据库的特征少于 1000 个,但我现在正在研究的那个有 >90,000 个特征。查询 1000 个特征需要 <1s,但查询 90,000 个特征需要 20 小时。这是因为它没有线性增长导致性能下降 80 倍:20*60*60/(90,000/1000) = 8000)
后端数据库使用 sqlite,我使用 sqliteodbc 连接器连接 excel。
如果我要在代码中执行此操作,我会这样做:
var features = featureRepository.GetAll();
var featuresWithMarkerDistance = new List<FeatureWithMarkerDistance>();
var previousMarker = null;
for(var index = 0; index < features.Length; index++) {
var currentFeature = features[index];
featuresWithMarkerDistance.Add(
new FeaturesWithMarkerDistance(currentFeature,
feature.distance - previousMarker.distance));
if(feature.is_marker) {
previousMarker = feature;
}
}
// FeatureWithMarkerDistance { int id, int distance, bool is_marker, int marker_distance }
// 编辑:
这是一个具体的例子:
(The underlying table)
feature_id is_marker distance
1 false 100
2 false 90
3 false 101
4 true 50
5 false 5
6 true 85
7 false 150
8 false 75
(有距离指数)
我想要的结果:
feature_id is_marker distance distance_to_closest_previous_marker
1 false 100 15
2 false 90 5
3 false 101 16
4 true 50 null
5 false 5 null
6 true 85 35
7 false 150 65
8 false 75 25
因此,如果我要获取 feature_id 1 的前一个标记,则 feature_id 1 的距离是 100,最近的标记是距离 85 处的 feature_id 6。要获得到最近的前一个标记的距离,我取 (100 - 85) = 15。我需要为要包含在报告中的每个功能获取此值。(这必须在单个 sql 查询中完成,因为我正在使用带有 excel 的 odbc 连接器)。上面的查询确实获取了我想要的内容,但它的性能非常糟糕,因为在 where 子句中它必须在整个数据库中搜索每个功能。
我想做的是:(除非有更高效的方式)
select *
/* I want all the data from this feature */
/* previous = */ (select MAX(f2.distance) - f1.distance
from feature as f2
where f2.is_marker && f2.distance >= previous && f2.distance < f1.distance)
/* and the distance to the previous marker */
from feature as f2
所以基本理论是我会存储前一个标记值,并且在我寻找下一个标记时只查看该值及之后的值。
对最初的混乱感到抱歉(我忘了把 MAX() 放在原来的位置)