使用 'LIKE '%' 的准备语句或即时生成查询哪个更好
Which is better between prepared statement with 'LIKE '%' or generate query on the fly
我正在实现一个典型的列表 Rest 端点 /items
,其中包含一些可选的过滤 URI 查询参数,例如 ?attr=val&attr2=val
等。
Rest 服务器由 Go/MySQL
支持
关于查询性能,我想知道创建一个使用 LIKE 语句的准备好的语句是否更好:
SELECT cols from items WHERE attr LIKE ? and attr2 LIKE ?;
并简单地将值设置为 '%'
到用户未填写的属性
或者根据给定的属性动态生成查询?
没有属性的例子:
SELECT cols from items;
具有一个属性的示例:
SELECT cols from items where attr LIKE 'val';
更一般地说,我想知道使用 LIKE '%'
是否会产生性能成本(考虑到在这些列上正确配置了索引)。如果与动态生成查询(解析等)的成本相比,这些性能成本在准备好的语句中是值得的。
注意:不同过滤属性的数量非常多,无法为每种可能的属性组合生成特定的准备语句。
查询时涉及三个部分。
- 正在解析查询。
- 根据查询结构和使用的参数值优化查询。
- 正在使用优化查询进行查询。
查询优化器在技术上可以将 LIKE '%'
优化为不使用 LIKE
的东西,但似乎 MySQL 没有这样做(但我不是 100%当然可以)。
对于布尔值,查询优化器会执行此类优化。
如果你这样做:
SELECT * FROM test WHERE (attr='val' OR TRUE) AND (attr2='val' OR FALSE);
结果查询将是:
SELECT * FROM test WHERE attr2='val';
因为 (attr='val' OR TRUE)
永远是 TRUE
,而 OR FALSE
什么都不做。
所以你总是可以有这样的东西:
SELECT * FROM test WHERE (attr=@attr OR !@useAttr) AND (attr2=@attr2 OR !@useAttr2);
和enable/disable使用布尔值的相应过滤器的用法。
如果值为 null
如果未设置,则类似这样:
SELECT * FROM test WHERE (attr=? OR ISNULL(?)) AND (attr2=? OR ISNULL(?));
然后像这样调用查询 stmnt.execute(attr, attr, attr2, attr2)
。
我建议您根据提供的数据花点时间构建查询。也就是说,构造 WHERE
子句仅包含用户要搜索的项目。
这可能会或可能不会真正加快速度,但它确实可以帮助您考虑 UI 并可能导致更好的 UI 设计。
当一列可能是,比方说,0 或 NULL 并且它们表示相同的东西时,使用 OR
会影响性能。相反,重新考虑模式——选择 0 或 NULL,而不是两者,作为任何指标。
如果您倾向于 LIKE '%xyz%'
,请考虑 FULLTEXT
索引是否更合适(而且速度更快)。
(同时,@t.niese 很好地讨论了优化。)
我正在实现一个典型的列表 Rest 端点 /items
,其中包含一些可选的过滤 URI 查询参数,例如 ?attr=val&attr2=val
等。
Rest 服务器由 Go/MySQL
支持关于查询性能,我想知道创建一个使用 LIKE 语句的准备好的语句是否更好:
SELECT cols from items WHERE attr LIKE ? and attr2 LIKE ?;
并简单地将值设置为 '%'
到用户未填写的属性
或者根据给定的属性动态生成查询?
没有属性的例子:
SELECT cols from items;
具有一个属性的示例:
SELECT cols from items where attr LIKE 'val';
更一般地说,我想知道使用 LIKE '%'
是否会产生性能成本(考虑到在这些列上正确配置了索引)。如果与动态生成查询(解析等)的成本相比,这些性能成本在准备好的语句中是值得的。
注意:不同过滤属性的数量非常多,无法为每种可能的属性组合生成特定的准备语句。
查询时涉及三个部分。
- 正在解析查询。
- 根据查询结构和使用的参数值优化查询。
- 正在使用优化查询进行查询。
查询优化器在技术上可以将 LIKE '%'
优化为不使用 LIKE
的东西,但似乎 MySQL 没有这样做(但我不是 100%当然可以)。
对于布尔值,查询优化器会执行此类优化。
如果你这样做:
SELECT * FROM test WHERE (attr='val' OR TRUE) AND (attr2='val' OR FALSE);
结果查询将是:
SELECT * FROM test WHERE attr2='val';
因为 (attr='val' OR TRUE)
永远是 TRUE
,而 OR FALSE
什么都不做。
所以你总是可以有这样的东西:
SELECT * FROM test WHERE (attr=@attr OR !@useAttr) AND (attr2=@attr2 OR !@useAttr2);
和enable/disable使用布尔值的相应过滤器的用法。
如果值为 null
如果未设置,则类似这样:
SELECT * FROM test WHERE (attr=? OR ISNULL(?)) AND (attr2=? OR ISNULL(?));
然后像这样调用查询 stmnt.execute(attr, attr, attr2, attr2)
。
我建议您根据提供的数据花点时间构建查询。也就是说,构造 WHERE
子句仅包含用户要搜索的项目。
这可能会或可能不会真正加快速度,但它确实可以帮助您考虑 UI 并可能导致更好的 UI 设计。
当一列可能是,比方说,0 或 NULL 并且它们表示相同的东西时,使用 OR
会影响性能。相反,重新考虑模式——选择 0 或 NULL,而不是两者,作为任何指标。
如果您倾向于 LIKE '%xyz%'
,请考虑 FULLTEXT
索引是否更合适(而且速度更快)。
(同时,@t.niese 很好地讨论了优化。)