2

プリアンブル (これは飛ばしてもかまいません。これは私の正当な理由です)

データベースのバックエンドとして sqlite を使用するアプリケーションを作成しました。スキーマは、一般的なアプリケーションの使用中に非常にうまく機能 (および実行) します。

今、私はそのためのレポート システムを構築しようとしています。名前のない DSN からクエリ テーブルを作成する Excel xll を構築しました。このため、すべてのレポートを SQL のみで行う必要があります (つまり、プログラムで何もできません)。これは、1 つのクエリを除いてすべてに対して非常にうまく機能します...

/// ここでスキップ....

私のデータベースには、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

2 回目の試行 (これは機能します。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 フィーチャのクエリには 1 秒未満かかりますが、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 を取得します。レポートに含めるすべての機能について、この値を取得する必要があります。(私は Excel で odbc コネクタを使用しているため、これは単一の SQL クエリで実行する必要があります)。上記のクエリは必要なものを取得しますが、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() を入れるのを忘れていました)

4

3 に答える 3

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
于 2012-07-13T23:35:33.207 に答える
0

SQLite はわかりませんが、このような動作はしますか (構文を調べたところ、LEFT JOIN と EXISTS が見つかりましたが、NOT 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 を持つ列の割合にも依存します)。

于 2012-07-13T22:41:22.970 に答える
0

私はSQLite3シェルを使用し、クエリを適応させてみました

SELECT *, 
       (SELECT MIN(feature.distance-distance) FROM feature AS f
               WHERE is_marker AND distance<feature.distance) 
       FROM feature;

5000 レコードでかなりのパフォーマンスを発揮しました。多分あなたの一番の弱点はsqliteobdcですか?それでも遅い場合は、真の is_marker がほとんどないと仮定すると、is_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;
于 2013-07-03T14:07:02.000 に答える