如何使用可变数量的WHERE表达式准备查询?

时间:2014-03-12 15:02:56

标签: sqlite sqlite3-ruby

我有一个如下所示的查询:

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

查询看起来很愚蠢,因为我希望能够通过WHERE部分中的任何列进行过滤,只要其余的列过滤器为NULL即可。例如,我可以使用上述查询搜索地址,方法是将{street_name: "foo", house_number: 12}{postal_code: 1234, house_number: 5}传递给同一个预准备语句,只要其余的键设置为nil。 / p>

此查询的问题是SQLite3显然无法使用数据库索引。此查询每秒仅运行6到8次。如果我将WHERE部分替换为WHERE sa.house_number = ? AND sn.name = ?并准备查询,则每秒运行超过110 000次。

我可以在每次运行时动态构建查询,但是为每次搜索引入了大量工作,并且失去了使用预准备语句的能力,将查询速度降低到每秒4000次运行。

要点:

在说服SQLite3使用索引进行速度优化时,有没有办法实现上述查询的效果?

1 个答案:

答案 0 :(得分:1)

使用多个与OR连接的术语,有效地使用索引is not possible

您绝对应该使用动态查询字符串。 如果您认为准备这些花费太长时间,请构建预准备语句的缓存,并将查询字符串作为键。 (预备语句使用的内存非常少。)