如何解决忽略DB2中空白的有效方法?
我正在大型IBM DB2数据库表中运行查询(我们称其为T),发现列标识符的单元格趋向于不仅填充在页边空白处,而且还填充在中间,例如:'ID1 ID2”。考虑到许多因素,我无权更新此数据库,也无权更新。但是,我想要一种忽略左右两侧空白的方法,即使我仅需在它们之间添加几个空格也是如此。以下查询有效,但是很慢,超过20秒很慢....
SELECT * FROM T WHERE Identifier LIKE '%ID1%ID2%';
SELECT * FROM T WHERE TRIM(Identifier) LIKE 'ID1%ID2';
SELECT * FROM T WHERE TRIM(Identifier) = 'ID1 ID2';
SELECT * FROM T WHERE LTRIM(RTRIM(Identifier)) = 'ID1 ID2';
SELECT * FROM T WHERE LTRIM(Identifier) LIKE 'ID1 ID2%';
SELECT * FROM T WHERE LTRIM(Identifier) LIKE 'ID1%ID2%';
SELECT * FROM T WHERE RTRIM(Identifier) LIKE '%ID1 ID2';
SELECT * FROM T WHERE RTRIM(Identifier) LIKE '%ID1%ID2';
尝试查询类似“ Select * FROM T WHERE REPLACE(Identifier,'','')...”之类的内容当然会冻结Access,直到我按Ctrl + Break结束操作为止。有没有更好,更有效的方法来忽略空白?
===============================
更新: 正如@Paul Vernon在下面描述的那样,“出于比较目的,在Db2中忽略了尾随空格,因此您只需要考虑前导空格和嵌入式空格。”
这导致我生成“ ID1”和“ ID2”之前的空格组合,并使用IN子句选择记录。组合的数量意味着查询比我知道确切匹配要慢。这就是我在使用Jdbc的Java代码中的外观(已对其进行编辑以使其对关键问题更加通用):
private static final int MAX_LENGTH = 30;
public List<Parts> queryMyTable(String ID1,String ID2) {
String query="SELECT * FROM MYTABLE WHERE ID IN (:ids)";
final Map<String,List<String>> parameters = getIDCombinations(ID1,ID2);
return namedJdbcTemplate.query(query,parameters,new PartsMapper());
}
public static List<String> getIDCombinations(String ID1,String ID2) {
List<String> combinations = new ArrayList<>();
final int literalLength = ID1.length() + ID2.length();
final int maxWhitespace = MAX_LENGTH - literalLength;
combinations.add(ID1+ID2);
for(int x = 1; x <= maxWhitespace; x++){
String xSpace = String.format("%1$"+x+"s","");
String idZeroSpaceBeforeBase = String.format("%s%s%s",ID1,xSpace,ID2);
String idZeroSpaceAfterBase = String.format("%s%s%s",ID2);
combinations.add(idZeroSpaceBeforeBase);
combinations.add(idZeroSpaceAfterBase);
for(int y = 1; (x+y) <= maxWhitespace; y++){
String ySpace = String.format("%1$"+y+"s","");
String id = String.format("%s%s%s%s",ySpace,ID2);
combinations.add(id);
}
}
return combinations;
}
解决方法
出于比较目的,在Db2中忽略了尾随空格,因此您只需要考虑前导空格和嵌入式空格。
假设now = datetime.datetime.now()
last_year = now - datetime.timedelta(days=365)
上有一个索引,您唯一的选择(如果您无法更改数据,添加功能索引或为生成的列建立索引)可能就是这样
Identifier
Db2优化可以将其实现为6个索引查找,这比完整索引或表扫描要快
您也可以尝试
SELECT * FROM T
WHERE
Identifier = 'ID1 ID2'
OR Identifier = ' ID1 ID2'
OR Identifier = ' ID1 ID2'
OR Identifier = 'ID1 ID2'
OR Identifier = ' ID1 ID2'
OR Identifier = ' ID1 ID2'
Db2优化可能会实现为3个索引范围扫描,
在两个示例中,如果需要,添加更多行以覆盖数据中前导空格的最大数目。在第一个示例中,如果需要,还为嵌入空间添加更多行
,表达式REGEXP_REPLACE(TRIM(Identifier),'\s{2,}',' ')
的索引和以下查询应使Db2使用此索引:
SELECT *
FROM T
WHERE REGEXP_REPLACE(TRIM(Identifier),' ') = 'ID1 ID2'
,
如果您需要搜索排除前导和尾随空格,那么至少在您展示情况下,没有任何传统索引可以帮助您。为了快速查询,我可以看到的选项是:
全文搜索
您可以使用“全文搜索”解决方案。 DB2确实包含此功能,但是我不记得它是默认包含在许可证中还是单独出售。无论如何,都需要对数据进行一点索引或定期重新索引,以确保搜索是最新的。如果您真的需要它,那是值得的。由于机制不同,您需要更改应用程序。
额外的干净列的索引
另一种解决方案是对没有前导或尾随空格的列进行索引。但是您需要创建一个额外的列;在大桌子上,此操作可能需要一些时间。好消息是,一旦创建,就不会再有延迟了。例如:
alter table t add column trimmed_id varchar(100)
generated always as (trim(identifier));
注意:您可能需要在此子句之前和之后禁用/启用对表的完整性检查。 DB2对此很挑剔。阅读手册,以确保它能正常工作。创建该列将需要一些时间。
然后,您需要对其进行索引:
create index ix1 on t (trimmed_id);
创建索引也将花费一些时间,但是它应该比上面的步骤要快。
现在,准备好了。您可以通过使用新列而不是原始列(仍然存在)来查询表,但是这次,您可以忽略前导和后继空格。例如:
SELECT * FROM T WHERE trimmed_id LIKE 'ID1%ID2';
现在唯一的通配符显示在中间。此查询将比读取整个表快得多。实际上,字符串ID1
越长,查询就会越快,因为选择性会更好。
现在,如果ID2
长于ID1
,则可以反转索引以使其更快。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。