Firebird 中查询执行缓慢
Slow query execution in Firebird
我执行的 SQL 查询如下:
update elements E
set E.END_I = (select n.node_num
from nodes N
where abs(E.X_I - N.XI) < 0.001 and
abs(E.Y_I - N.YI) < 0.001 and
abs(E.Z_I - N.ZI) < 0.001
)
大约需要 24 秒才能完成,我阅读了有关 firebird 故障排除的信息 Why is my database query slow? 它指示为 table 中的相关字段创建索引,我已经添加了 decreasing/increasing 索引对于节点和元素 table 中的 XI、YI、ZI 字段。但性能仍然很慢,数据库中有 6677 行,我使用 FlameRobin 作为 SQL 编辑器。
有趣的是:如 Firebird 故障排除指南中所述
If you see a NATURAL plan going against a big table, you've found the
problem
此错误被描述为坏情况和减速源,推荐的解决方案是为相关字段创建递减索引。但在我的例子中,即使在定义了索引之后,我似乎仍然受到 Flamerobin 输出中报告的 PLAN (N NATURAL)、PLAN (E NATURAL) 的困扰,如下所示。
我该如何消除它?
Preparing query: update elements E set E.END_I = (select n.node_num from nodes N
where abs(E.X_I-N.XI)<0.001 and abs(E.Y_I - N.YI)<0.001 and abs(E.Z_I-N.ZI)<0.001 )
Prepare time: 0.004s
PLAN (N NATURAL)
PLAN (E NATURAL)
Executing...
Done.
108818273 fetches, 79227 marks, 4050 reads, 9380 writes.
0 inserts, 6677 updates, 0 deletes, 0 index, 14549183 seq.
Delta memory: 212 bytes.
ELEMENTS: 6677 updates.
6677 rows affected directly.
Total execution time: 24.038s
Script execution finished.
CREATE DESCENDING INDEX IDX_ELEMENTS1 ON ELEMENTS (Z_I);
CREATE DESCENDING INDEX IDX_XI ON ELEMENTS (X_I);
CREATE DESCENDING INDEX IDX_YI ON ELEMENTS (Y_I);
GRANT DELETE, INSERT, REFERENCES, SELECT, UPDATE
ON ELEMENTS TO SYSDBA WITH GRANT OPTION;
CREATE DESCENDING INDEX IDX_NODES1_XI ON NODES (XI);
CREATE DESCENDING INDEX IDX_NODES1_YI ON NODES (YI);
CREATE DESCENDING INDEX IDX_NODES1_ZI ON NODES (ZI);
GRANT DELETE, INSERT, REFERENCES, SELECT, UPDATE
ON NODES TO SYSDBA WITH GRANT OPTION;
abs()
函数降低了您的查询速度,因为裸列上的索引不适用于表达式。
尝试更改查询以至少让数据库有机会使用索引
update elements E
set E.END_I = (select n.node_num
from nodes N
where N.XI < E.X_I + 0.001 AND N.XI > E.X_I - 0.001
AND N.YI < E.Y_I + 0.001 AND N.YI > E.Y_I - 0.001
AND N.ZI < E.Z_I + 0.001 AND N.ZI > E.Z_I - 0.001
)
在列 X_I、Y_I、Z_I 上创建索引,然后 运行 语句:
MERGE INTO elements dst
USING (
SELECT e.x_i, e.y_i, e.z_i, n.node_num
FROM nodes N JOIN elements E ON
abs(E.X_I - N.XI) < 0.001 and
abs(E.Y_I - N.YI) < 0.001 and
abs(E.Z_I - N.ZI) < 0.001
) src
ON dst.X_I = src.X_I AND dst.Y_I = src.Y_I AND dst.Z_I = src.Z_I
WHEN MATCHED THEN UPDATE SET dst.END_I = src.NODE_NUM
如此处的答案所述,您可以删除 ABS 函数并在 N 的 XI、YI、ZI 列上创建索引 table 以进一步加快进程。
也许这样的事情可以帮助:
1) 创建表格之间的笛卡尔积,计算X、Y和Z。
2) 只过滤需要的记录。
3) 用 node_num 值更新元素记录。
execute block
as
declare variable key integer; -- primary key type
declare variable node_num integer; -- node_num type
begin
for
select
key,
node_num
from (
select
E.key, -- primary key name
N.node_num,
abs(E.X_I - N.XI) as X,
abs(E.Y_I - N.YI) as Y,
abs(E.Z_I - N.ZI) as Z
from elements E, nodes N)
where (X < 0.001)
and (Y < 0.001)
and (Z < 0.001)
into
:key,
:node_num
do
begin
update elements set
END_ID = :node_num
where elements.key = :key; -- primary key name
end
end
我执行的 SQL 查询如下:
update elements E
set E.END_I = (select n.node_num
from nodes N
where abs(E.X_I - N.XI) < 0.001 and
abs(E.Y_I - N.YI) < 0.001 and
abs(E.Z_I - N.ZI) < 0.001
)
大约需要 24 秒才能完成,我阅读了有关 firebird 故障排除的信息 Why is my database query slow? 它指示为 table 中的相关字段创建索引,我已经添加了 decreasing/increasing 索引对于节点和元素 table 中的 XI、YI、ZI 字段。但性能仍然很慢,数据库中有 6677 行,我使用 FlameRobin 作为 SQL 编辑器。
有趣的是:如 Firebird 故障排除指南中所述
If you see a NATURAL plan going against a big table, you've found the problem
此错误被描述为坏情况和减速源,推荐的解决方案是为相关字段创建递减索引。但在我的例子中,即使在定义了索引之后,我似乎仍然受到 Flamerobin 输出中报告的 PLAN (N NATURAL)、PLAN (E NATURAL) 的困扰,如下所示。
我该如何消除它?
Preparing query: update elements E set E.END_I = (select n.node_num from nodes N
where abs(E.X_I-N.XI)<0.001 and abs(E.Y_I - N.YI)<0.001 and abs(E.Z_I-N.ZI)<0.001 )
Prepare time: 0.004s
PLAN (N NATURAL)
PLAN (E NATURAL)
Executing...
Done.
108818273 fetches, 79227 marks, 4050 reads, 9380 writes.
0 inserts, 6677 updates, 0 deletes, 0 index, 14549183 seq.
Delta memory: 212 bytes.
ELEMENTS: 6677 updates.
6677 rows affected directly.
Total execution time: 24.038s
Script execution finished.
CREATE DESCENDING INDEX IDX_ELEMENTS1 ON ELEMENTS (Z_I);
CREATE DESCENDING INDEX IDX_XI ON ELEMENTS (X_I);
CREATE DESCENDING INDEX IDX_YI ON ELEMENTS (Y_I);
GRANT DELETE, INSERT, REFERENCES, SELECT, UPDATE
ON ELEMENTS TO SYSDBA WITH GRANT OPTION;
CREATE DESCENDING INDEX IDX_NODES1_XI ON NODES (XI);
CREATE DESCENDING INDEX IDX_NODES1_YI ON NODES (YI);
CREATE DESCENDING INDEX IDX_NODES1_ZI ON NODES (ZI);
GRANT DELETE, INSERT, REFERENCES, SELECT, UPDATE
ON NODES TO SYSDBA WITH GRANT OPTION;
abs()
函数降低了您的查询速度,因为裸列上的索引不适用于表达式。
尝试更改查询以至少让数据库有机会使用索引
update elements E
set E.END_I = (select n.node_num
from nodes N
where N.XI < E.X_I + 0.001 AND N.XI > E.X_I - 0.001
AND N.YI < E.Y_I + 0.001 AND N.YI > E.Y_I - 0.001
AND N.ZI < E.Z_I + 0.001 AND N.ZI > E.Z_I - 0.001
)
在列 X_I、Y_I、Z_I 上创建索引,然后 运行 语句:
MERGE INTO elements dst
USING (
SELECT e.x_i, e.y_i, e.z_i, n.node_num
FROM nodes N JOIN elements E ON
abs(E.X_I - N.XI) < 0.001 and
abs(E.Y_I - N.YI) < 0.001 and
abs(E.Z_I - N.ZI) < 0.001
) src
ON dst.X_I = src.X_I AND dst.Y_I = src.Y_I AND dst.Z_I = src.Z_I
WHEN MATCHED THEN UPDATE SET dst.END_I = src.NODE_NUM
如此处的答案所述
也许这样的事情可以帮助:
1) 创建表格之间的笛卡尔积,计算X、Y和Z。
2) 只过滤需要的记录。
3) 用 node_num 值更新元素记录。
execute block
as
declare variable key integer; -- primary key type
declare variable node_num integer; -- node_num type
begin
for
select
key,
node_num
from (
select
E.key, -- primary key name
N.node_num,
abs(E.X_I - N.XI) as X,
abs(E.Y_I - N.YI) as Y,
abs(E.Z_I - N.ZI) as Z
from elements E, nodes N)
where (X < 0.001)
and (Y < 0.001)
and (Z < 0.001)
into
:key,
:node_num
do
begin
update elements set
END_ID = :node_num
where elements.key = :key; -- primary key name
end
end