序言(你可以跳过这个,这只是我的理由)
我创建了一个使用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
第二次尝试(这个有效,只需要WAAAY太长时间就可以获得100,000个功能,大约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个功能的查询需要&lt; 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())
答案 0 :(得分:0)
不知道SQLite,但做了类似的工作(我查找语法,找到LEFT JOIN和EXISTS,但不是不存在)?
select f2.*, f2.distance - f1.distance
from feature f2
left join feature f1 on f1.is_marker
and f2.distance > f1.distance
and not exists(select 1 from feature f1b
where f1b.is_marker
and f2.distance > f1b.distance
and f1.distance < f1b.distance)
where f2.is_marker
我对性能没有任何线索,但是期望(is_marker,distance)上的索引可能是有利的(你必须测试是否在索引中包含is_marker是否有用,除此之外取决于SQLite,它可能还取决于具有is_marker = true的列的百分比。
答案 1 :(得分:0)
这些例子确实有帮助。你走了。
SELECT F2.feature_id, F2.is_marker, F2.distance,
F2.distance - (SELECT F1.distance FROM features F1
WHERE F1.is_marker<>0
AND F1.distance<F2.distance
ORDER BY F1.distance DESC
LIMIT 1) AS "distance_to_closest_previous_marker"
FROM features F2
答案 2 :(得分:0)
我使用了SQLite3 shell,我尝试了你的查询改编
SELECT *,
(SELECT MIN(feature.distance-distance) FROM feature AS f
WHERE is_marker AND distance<feature.distance)
FROM feature;
它在5000条记录中表现相当不错。也许你最薄弱的地方是sqliteobdc? 如果确实它仍然很慢,并且假设你的is_marker很少,那么你可以创建一个只有距离feature_marker为真的特征的表:
CREATE TEMP TABLE markers_distance (distance);
CREATE UNIQUE INDEX markers_idx ON markers_distance (distance);
INSERT OR IGNORE INTO markers_distance
SELECT distance FROM feature WHERE is_marker;
现在您对markers_distance的查询应该更快:
SELECT *,
(SELECT MIN(feature.distance-distance) FROM markers_distance
WHERE distance<feature.distance)
FROM feature;