1

誰かが「CASEWHEN」がそれをとても遅くする理由とそれを最適化/修正する方法を教えてもらえますか?

固定されたアイテムを結果の最初に順番に配置する必要があります。

私はおそらくSQLクエリの後でそれを行うことができますが、このソートがSQLクエリ内で行われる場合、正しく実行された場合、より高速になると思います。

遅いクエリ〜490ms

SELECT 
    places.id AS place_id,
    url,
    title,
    thumbnails.score AS score,
    thumbnails.clipping AS clipping,
    thumbnails.lastModified AS lastModified,
    EXISTS (SELECT 1 FROM pinned pi WHERE pi.place_id = places.id) AS pinned
FROM places
    LEFT JOIN thumbnails ON (thumbnails.place_id = places.id)
    LEFT JOIN pinned j ON (j.place_id = places.id) WHERE (hidden == 0)
ORDER BY case when j.id is null then 1 else 0 end,
    j.id,
    frecency DESC LIMIT 24

'CASE WHEN'部分の削除:クエリ〜6ms

SELECT
    places.id AS place_id,
    url,
    title,
    thumbnails.score AS score,
    thumbnails.clipping AS clipping,
    thumbnails.lastModified AS lastModified,
    EXISTS (SELECT 1 FROM pinned pi WHERE pi.place_id = places.id) AS pinned
FROM places
    LEFT JOIN thumbnails ON (thumbnails.place_id = places.id) WHERE (hidden == 0)
ORDER BY frecency DESC LIMIT 24

テーブル情報:

var Create_Table_Places =
    'CREATE TABLE places (' +
        'id INTEGER PRIMARY KEY,' +
        'url LONGVARCHAR,' +
        'title LONGVARCHAR,' +
        'visit_count INTEGER DEFAULT 0,' +
        'hidden INTEGER DEFAULT 0 NOT NULL,' +
        'typed INTEGER DEFAULT 0 NOT NULL,' +
        'frecency INTEGER DEFAULT -1 NOT NULL,' +
        'last_visit_date INTEGER,' +
        'dateAdded INTEGER,' +
        'lastModified INTEGER' +
    ')';

var Create_Table_Thumbnails =
    'CREATE TABLE thumbnails (' +
        'id INTEGER PRIMARY KEY,' +
        'place_id INTEGER UNIQUE,' +
        'data LONGVARCHAR,' +
        'score REAL,' +
        'clipping INTEGER,' +
        'dateAdded INTEGER,' +
        'lastModified INTEGER' +
    ')';

var Create_Table_Pinned =
    'CREATE TABLE pinned (' +
        'id INTEGER PRIMARY KEY,' +
        'place_id INTEGER UNIQUE,' +
        'position INTEGER,' +
        'dateAdded INTEGER,' +
        'lastModified INTEGER' +
    ')';
4

1 に答える 1

1

クエリの実行に根本的な違いがあるかどうかを確認するには、 を使用しますEXPLAIN QUERY PLAN。SQLite 3.7.almost15 では、クエリには次のプランがあります。

selectid order from detail
-------- ----- ---- ------
0        0     0    SCAN TABLE places (~100000 rows)
0        1     1    SEARCH TABLE thumbnails USING INDEX sqlite_autoindex_thumbnails_1 (place_id=?) (~1 rows)
0        2     2    SEARCH TABLE pinned AS j USING COVERING INDEX sqlite_autoindex_pinned_1 (place_id=?) (~1 rows)
0        0     0    EXECUTE CORRELATED SCALAR SUBQUERY 1
1        0     0    SEARCH TABLE pinned AS pi USING COVERING INDEX sqlite_autoindex_pinned_1 (place_id=?) (~1 rows)
0        0     0    USE TEMP B-TREE FOR ORDER BY

selectid order from detail
-------- ----- ---- ------
0        0     0    SCAN TABLE places (~100000 rows)
0        1     1    SEARCH TABLE thumbnails USING INDEX sqlite_autoindex_thumbnails_1 (place_id=?) (~1 rows)
0        0     0    EXECUTE CORRELATED SCALAR SUBQUERY 1
1        0     0    SEARCH TABLE pinned AS pi USING COVERING INDEX sqlite_autoindex_pinned_1 (place_id=?) (~1 rows)
0        0     0    USE TEMP B-TREE FOR ORDER BY

pinnedこれら 2 つのプランは、ルックアップが重複していることを除けば、ほとんど同じです。SQLite がこの方法でクエリを実行しない場合は、更新してください。

pinned最初のクエリでは、既にテーブルと結合しているため、フィールドのサブクエリを削除できますpinned。また、結合に対して行われたのとまったく同じルックアップを実行しています。代わりに使用j.id IS NOT NULLします。

他の値の後に s をソートCASE WHENする目的がありNULLます。すべての sを、文字列などのnumbers の後にソートされる値に変換するNULLことで、同じ効果を得ることができます。

... ORDER BY IFNULL(j.id, ''), frecency DESC

ただし、理論的には、これは との実行時の違いはあまりないはずCASE WHENです。

于 2012-10-23T19:36:23.907 に答える