0

次のようなクエリがあります。

SELECT
  sn.name,           -- Street name
  sa.house_number,   -- House number
  sa.entrance,       -- Entrance
  pc.postal_code,    -- Postal code
  ci.name,           -- City
  mu.name,           -- Municipality
  co.name            -- County
FROM
  street_addresses AS sa
    INNER JOIN street_names   AS sn ON sa.street_name  = sn.id
    INNER JOIN postal_codes   AS pc ON sa.postal_code  = pc.id
    INNER JOIN cities         AS ci ON sa.city         = ci.id
    INNER JOIN municipalities AS mu ON sa.municipality = mu.id
    INNER JOIN counties       AS co ON mu.county       = co.id
WHERE
  (:id           IS NULL OR sa.id           = :id) AND
  (:street_name  IS NULL OR sn.name         = :street_name) AND
  (:house_number IS NULL OR sa.house_number = :house_number) AND
  (:entrance     IS NULL OR sa.entrance     = :entrance) AND
  (:postal_code  IS NULL OR pc.postal_code  = :postal_code) AND
  (:city         IS NULL OR ci.name         = :city) AND
  (:municipality IS NULL OR mu.name         = :municipality) AND
  (:county       IS NULL OR co.name         = :county)
ORDER BY
  sn.name ASC, sa.house_number ASC, sa.entrance ASC

残りの列フィルターが NULL である限り、WHERE セクションの任意の列でフィルター処理できるようにしたいので、クエリはこれほどばかげているように見えます。たとえば、残りのキーが に設定されている限り、同じ準備済みステートメントに{street_name: "foo", house_number: 12}またはを渡すことにより、上記のクエリを使用してアドレスを検索できます。{postal_code: 1234, house_number: 5}nil

このクエリの問題は、SQLite3 が明らかにデータベース インデックスの使用に失敗していることです。このクエリは、1 秒あたり 6 ~ 8 回しか実行されません。WHEREセクションを次のように置き換えてWHERE sa.house_number = ? AND sn.name = ?クエリを準備すると、1 秒あたり 110,000 回以上実行されます。

クエリを実行するたびにクエリを動的に作成することもできますが、検索ごとにそれだけ多くの作業を導入し、さらに準備済みステートメントを使用する機能を失うと、クエリの速度が 1 秒あたり約 4000 回の実行に低下します。

概要:

速度の最適化のためにインデックスを使用するように SQLite3 を納得させながら、上記のクエリの効果を達成する方法はありますか?

4

1 に答える 1

1

多数の OR 接続された用語があるため、インデックスを効率的に使用することはできません

必ず動的クエリ文字列を使用する必要があります。これらの準備に時間がかかりすぎると思われる場合は、クエリ文字列をキーとして、準備済みステートメントのキャッシュを構築します。(準備済みステートメントはほとんどメモリーを使用しません。)

于 2014-03-12T17:10:47.900 に答える