忽略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,则可以反转索引以使其更快。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...