简体   繁体   English

在Firebird中执行速度慢

[英]Slow query execution in Firebird

My executed SQL query is as follow : 我执行的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
                  )

It takes about 24 secs to complete, I read about firebird troubleshooting Why is my database query slow? 它需要大约24秒才能完成,我读到了关于firebird故障排除为什么我的数据库查询速度慢? 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. 它指示为表中的相关字段创建索引,并且我在两个节点和元素表中添加了XI,YI,ZI字段的递减/递增索引。 But still the performance is very slow, there 6677 rows in database and I'm using the FlameRobin as SQL editor. 但是性能仍然很慢,数据库中有6677行,我使用FlameRobin作为SQL编辑器。

Interesting thing is: As depicted in Firebird troubleshooting guide having 有趣的是:正如Firebird故障排除指南所描述的那样

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. 但在我的情况下,即使在定义指数之后,似乎我仍然受到计划(N NATURAL),PLAN(E NATURAL)的影响,这在Flamerobin输出中报告如下所示。

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. abs()函数会减慢您的查询,因为裸列上的索引不能与表达式一起使用。 Try changing the query to at least give the db a chance to use an index 尝试更改查询以至少为db提供使用索引的机会

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: 在列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

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. 正如在https://stackoverflow.com/a/34656659/55350的答案中所提到的,你可以摆脱ABS功能并在N表的第XI,YI,ZI列上创建索引,以进一步加快进程。

Maybe something like this could help: 也许这样的事情可以帮助:

1) Create a cartesian product between tables, calculating X, Y and Z. 1)在表格之间创建笛卡尔积,计算X,Y和Z.

2) Filter just desired records. 2)过滤所需的记录。

3) Update elements records with node_num value. 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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