我有一个如下所示的查询:
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使用索引进行速度优化时,有没有办法实现上述查询的效果?
答案 0 :(得分:1)
使用多个与OR连接的术语,有效地使用索引is not possible。
您绝对应该使用动态查询字符串。 如果您认为准备这些花费太长时间,请构建预准备语句的缓存,并将查询字符串作为键。 (预备语句使用的内存非常少。)