Reputation: 399
My executed SQL query is as follow :
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
)
It takes about 24 secs to complete, I read about firebird troubleshooting Why is my database query slow? It instructs to create indices for the related fields in table and I've added the decreasing/increasing indices for the XI, YI, ZI fields in both of the Nodes and Elements tables. But still the performance is very slow, there 6677 rows in database and I'm using the FlameRobin as SQL editor.
Interesting thing is: As depicted in Firebird troubleshooting guide having
If you see a NATURAL plan going against a big table, you've found the problem
this error is described as bad case and source of slow down, recommended solution is, create decreasing indices for related fields. But in my case even after defining the indices it seems that I'm still suffering from that PLAN (N NATURAL), PLAN (E NATURAL) which is reported in Flamerobin output as shown below.
How am I supposed to eliminate that?
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;
Upvotes: 4
Views: 2233
Reputation: 71
Maybe something like this could help:
1) Create a cartesian product between tables, calculating X, Y and Z.
2) Filter just desired records.
3) Update elements records with node_num value.
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
Upvotes: 0
Reputation: 5481
Create indices on columns X_I, Y_I, Z_I, then run statement:
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
As mentioned in the answer here https://stackoverflow.com/a/34656659/55350 you could get rid of ABS functions and create indices on columns XI, YI, ZI of N table to further speed up a process.
Upvotes: 0
Reputation: 16467
Your query is slowed down by the abs()
function as the index on bare column doesn't work with expressions.
Try changing the query to at least give the db a chance to use an index
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
)
Upvotes: 2