加快 Informix 的 SQL 查询?

Speed up SQL query for Informix?

在 Informix 上,是否可以加快此查询的速度?

SELECT FIRST 1 HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1  as dec,
           HEX(HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1) as hex,
   SUBSTR((HEX(HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1))::char(10), 6) as str
FROM informix.coordman as l
WHERE (SUBSTR(NVL(l.cm_code, ' '), 1, 2) = 'MU')
AND
NOT EXISTS (SELECT r.cm_code FROM informix.coordman r
            WHERE (SUBSTR(NVL(l.cm_code, ' '), 1, 2) = 'MU') AND
                  (SUBSTR(NVL(r.cm_code, ' '), 1, 2) = 'MU') AND
                  (HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1 =
                   HEX('0x'||SUBSTR(LPAD(NVL(r.cm_code, '0'), 7, '0') , 3))::INT) )
ORDER BY 1 ASC;

我已经尝试过带有 LEFT OUTER JOIN,

的版本
SELECT FIRST 1 HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1 as dec,
HEX(HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1) as hex,
SUBSTR((HEX(HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1))::char(10), 6) as str,
r.cm_code
FROM informix.coordman as l
LEFT OUTER JOIN informix.coordman r ON
(SUBSTR(NVL(l.cm_code, ' '), 1, 2) = 'MU') AND
(SUBSTR(NVL(r.cm_code, ' '), 1, 2) = 'MU') AND
(HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1 =
HEX('0x'||SUBSTR(LPAD(NVL(r.cm_code, '0'), 7, '0') , 3))::INT)
WHERE (SUBSTR(NVL(l.cm_code, ' '), 1, 2) = 'MU') and
r.cm_code IS NULL
ORDER BY 1 ASC;

但是我把速度变差了

更新 查询的目的是在如下所示的序列中找到漏洞:

cm_code
MU00001
MU00001
MU00002
MU00002
...
MU0000B
MU0000B
MU0000D
MU0000D
...
MU00010
MU00010
MU00011

cm_code 字段的类型是:

Column name          Type                                    Nulls
cm_code              char(8)                                 yes

为了加快速度,之前上报的查询已替换为:

SELECT FIRST 1 HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1 as dec, 
HEX(HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1) as hex, 
SUBSTR((HEX(HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1))::char(10), 6) as str 
FROM 
informix.coordman as l WHERE 
(SUBSTR(NVL(l.cm_code, ' '), 1, 2) = 'MU') 
ORDER BY 1 ASC

现在我需要加快下面的查询:

SELECT FIRST 1 HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT + 1 as dec, 
HEX(HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT + 1) as hex, 
SUBSTR((HEX(HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT + 1))::char(10), 6) as str 
FROM 
informix.coordman as l WHERE 
(SUBSTR(NVL(l.cm_code, ' '), 1, 2) = 'MU') AND 
NOT EXISTS (SELECT r.cm_code FROM informix.coordman r WHERE 
(SUBSTR(NVL(l.cm_code, ' '), 1, 2) = 'MU') AND 
(SUBSTR(NVL(r.cm_code, ' '), 1, 2) = 'MU') AND 
(HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT +1 = HEX('0x'||SUBSTR(LPAD(NVL(r.cm_code, '0'), 7, '0') , 3))::INT)) 
ORDER BY 1 ASC

我已经为您的查询制作了两个版本,一个需要 Informix 14.10,一个不需要。我已经根据您的查询对它们进行了基准测试,结果非常显着。我使用的是随机生成的 table,其中包含 360 行。对于一组数据,这导致数字出现一次的85行,出现两次的67行,出现三次的26行,出现四次的8行,出现五次的5行,出现六次的1行

结果:

Q0      0.7212 seconds — as in question
Q1      0.0044 seconds — using CTE
Q2      0.0027 seconds — using an explicit temporary table
                        (add 0.0006 seconds if the temp table is dropped explicitly)

我不知道为什么Q1和Q2之间有这么大的差异,但与Q0相比都可以忽略不计。

这个 SQL 脚本,显示我执行的内容,需要我的 SQLCMD 程序,可从 IIUG (International Informix Users Group。它还使用自制随机数据生成器。

!random -n 360 -F "MU%5X" 1 255 > "so-5575-9624.unl"

DROP TABLE IF EXISTS coordman;
CREATE TABLE coordman
(
    cm_code CHAR(8) NOT NULL
);

RELOAD FROM "so-5575-9624.unl" INSERT INTO coordman;
CREATE INDEX i_cm_code ON coordman(cm_code);

types on;
headings on;
trace on;

--SELECT {FIRST 1}   HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1  AS DEC,
SELECT DISTINCT    HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1  AS DEC,
               HEX(HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1) AS HEX,
       SUBSTR((HEX(HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1))::CHAR(10), 6) AS str
  FROM coordman AS l
 WHERE (SUBSTR(NVL(l.cm_code, ' '), 1, 2) = 'MU')
   AND NOT EXISTS
       (SELECT r.cm_code FROM coordman AS r
         WHERE (SUBSTR(NVL(l.cm_code, ' '), 1, 2) = 'MU') AND
               (SUBSTR(NVL(r.cm_code, ' '), 1, 2) = 'MU') AND
               (HEX('0x'||SUBSTR(LPAD(NVL(l.cm_code, '0'), 7, '0') , 3))::INT - 1 =
                HEX('0x'||SUBSTR(LPAD(NVL(r.cm_code, '0'), 7, '0') , 3))::INT)
       )
ORDER BY 1 ASC;

WITH cm_numbers AS
     (SELECT DISTINCT cm_code,
            --('0x'||cm_code[3,8])               AS hex_string,
            --('0x'||cm_code[3,8])::INT          AS dec_value,
            --('0x'||SUBSTR(cm_code, 3, 6))      AS hex_substr,
            ('0x'||SUBSTR(cm_code, 3, 6))::INT AS dec_number
       FROM coordman AS l
      WHERE cm_code[1,2] = "MU"
     )
SELECT l.dec_number - 1 AS missing_number, l.cm_code
  FROM cm_numbers AS l
  LEFT JOIN cm_numbers AS r
    ON l.dec_number - 1 = r.dec_number
 WHERE r.dec_number IS NULL
 ORDER BY missing_number;

DROP TABLE IF EXISTS cm_numbers;

SELECT DISTINCT cm_code, ('0x'||SUBSTR(cm_code, 3, 6))::INT AS dec_number
  FROM coordman AS l
 WHERE cm_code[1,2] = "MU"
  INTO TEMP cm_numbers;

SELECT l.dec_number - 1 AS missing_number, l.cm_code
  FROM cm_numbers AS l
  LEFT JOIN cm_numbers AS r
    ON l.dec_number - 1 = r.dec_number
 WHERE r.dec_number IS NULL
 ORDER BY missing_number;

DROP TABLE IF EXISTS cm_numbers;

主要区别在于调用的函数数量之多。此外,如评论中所述,您可以使用 NVL 防止空值,但您不使用它的作用 return.