简体   繁体   中英

Slow query execution in Firebird

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;

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
                  )

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM