加快 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.
在 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.