【问题标题】:Is this postgres function cost efficient or still have to clean这个 postgres 功能是否具有成本效益或仍然需要清理
【发布时间】:2010-12-30 12:59:16
【问题描述】:

postgres 数据库中有两个表。 English_all 和 english_glob

第一个表包含诸如国际、机密、启动、冷却器......等词

我已经编写了从english_all 中获取单词的函数,然后对每个单词执行for 循环以获取未插入到anglish_glob 表中的单词列表。单词列表就像

I
In
Int
Inte
Inter
..
b
bo
boo
boot
..
c
co
coo
cool
etc..

由于某种原因,zwnj(zero-width non-joiner) 在插入到english_all 表的过程中被添加。 但在函数中,我正在使用 regexp_replace 删除该字符。

Postgres 函数 for_loop_test 采用两个参数 min 和 max,基于我从english_all 表中选择单词。

功能码是这样的

DECLARE
inMinLength ALIAS FOR $1;
inMaxLength ALIAS FOR $2;
mviews RECORD;
outenglishListRow english_word_list;--custom data type eng_id,english_text
BEGIN
FOR mviews IN SELECT id,english_all_text FROM english_all where wlength between inMinLength and inMaxLength 
ORDER BY english_all_text limit 30 LOOP

FOR i IN 1..char_length(regexp_replace(mviews.english_all_text,'(‌)$','')) LOOP
    FOR outenglishListRow IN
        SELECT distinct on (regexp_replace((substring(mviews.english_all_text from 1 for i)),'(‌)$','')) mviews.id,
        regexp_replace((substring(mviews.english_all_text from 1 for i)),'(‌)$','') where 
        regexp_replace((substring(mviews.english_all_text from 1 for i)),'(‌)$','') not 
        in(select english_glob.english_text from english_glob where i=english_glob.wlength)
        order by regexp_replace((substring(mviews.english_all_text from 1 for i)),'(‌)$','')
    LOOP
    RETURN NEXT outenglishListRow;
    END LOOP;


END LOOP;
END LOOP;
END;

一旦我得到单词列表,我会将它插入另一个表english_glob。 我的问题是我可以在函数中添加或删除任何东西以提高效率。

编辑 假设english_all 表有像

这样的词
  • 页脚、解决、问题、溢出、数据库、王国

如果 inMinLength = 5 并且 inmaxLength=7 然后在外循环中

  • 页脚,定居,王国

将被选中。 对于以上 3 个单词,内两个循环将适用于获取类似的单词

  • f,fo,foo,foot,foote,footer,s,se,set,sett,settl ......等等。

在最后的过程中,加粗的单词将被输入到english_glob,并带有另一个参数,例如1,表示它是一个正确的单词,并存储在english_glob表的另一个字段中。剩余的单词将与另一个参数 0 一起存储,因为在下次调用时不应再次提取保存在数据库中的单词。

编辑2: 这是完整的代码

CREATE TABLE english_all
(
id serial NOT NULL,
english_all_text  text NOT NULL,
wlength integer NOT NULL,
CONSTRAINT english_all PRIMARY KEY (id),
CONSTRAINT english_all_kan_text_uq_id UNIQUE (english_all_text)
)

CREATE TABLE english_glob
(
id serial NOT NULL,
english_text  text NOT NULL,
is_prop integer default 1,
CONSTRAINT english_glob PRIMARY KEY (id),
CONSTRAINT english_glob_kan_text_uq_id UNIQUE (english_text)
)

insert into english_all(english_all_text,wlength) values ('ant',char_length('ant')),('forget',char_length('forget')),('forgive',char_length('forgive'));

在函数调用时,应获取参数 3 和 6 个闲置行

a
an
ant
f
fo
for
forg
forge
forget

下一步是根据上面的行插入另一个表

insert into english_glob(english_text,is_prop) 
values 
('a',1),('an',1),
('ant',1),('f',0),
('fo',0),('for',1),
('forg',0),('forge',1),
('forget',1),

下次调用函数时,参数 3 和 7 的闲置行应该被获取。(因为 f,fo,for,forg 都输入到english_glob 表中)

forgi
forgiv
forgive

Screenshot

【问题讨论】:

  • 如果您正在使用循环逻辑查看最快的方式,那么您并没有采用最快的方式。在大多数情况下尽可能使用直接 SQL 尝试并重新工作以使用直接 SQL,这是可能的并且将是最快的。边缘情况你可能需要使用一些 PL。
  • 感谢您的代码。您正在将 1 插入到 is_prop 中,以获取单词 aanantforforgeforgetPostgreSQL 如何知道它们是正确的英文单词并用1 标记它们?

标签: function postgresql performance nested-loops


【解决方案1】:

您可以在一个语句中完成:

SELECT  english_all_text, part,
        part IN
        (
        SELECT  english_text
        FROM    english_glob
        ) AS found
FROM    (
        SELECT  *, SUBSTRING(english_all_text, 1, generate_series(1, LENGTH(english_all_text))) AS part
        FROM    english_all
        WHERE   LENGTH(english_all_text) BETWEEN 5 AND 7
        ) q

一些要检查的示例数据:

WITH    english_all(english_all_text) AS
        (
        SELECT  unnest('{footer,settle,question,overflow,database,kingdom}'::text[])
        ),
        english_glob(english_text) AS
        (
        SELECT  unnest('{foot,footer,set}'::text[])
        )
SELECT  english_all_text, part,
        part IN
        (
        SELECT  english_text
        FROM    english_glob
        ) AS found
FROM    (
        SELECT  *, SUBSTRING(english_all_text, 1, generate_series(1, LENGTH(english_all_text))) AS part
        FROM    english_all
        WHERE   LENGTH(english_all_text) BETWEEN 5 AND 7
        ) q

更新:

如果您只需要返回部分不在列表中的单词,请使用:

SELECT  part
FROM    (
        SELECT  *, SUBSTRING(english_all_text, 1, generate_series(1, LENGTH(english_all_text))) AS part
        FROM    english_all
        WHERE   LENGTH(english_all_text) BETWEEN 5 AND 7
        ) q
WHERE   part NOT IN
        (
        SELECT  english_text
        FROM    english_glob
        )

【讨论】:

  • @Quassnoi 根本不起作用。该查询只是返回english_all 表中的所有行。函数参数inMinLength 和inMaxLength 也不包含在您的查询本身中。
  • @kiranking:能否请您从两个表和预期输出中发布一些示例数据?
  • @Quassnoi 请检查已编辑的问题。数据获取没有问题,但我关心的是嵌套的 for 循环。效率高还是我还得调。
  • @kiranking:请查看查询更新。您能否发布您所追求的结果集,而不是口头描述:口头描述可能会令人困惑。
  • @Quassnoi 我用所需的结果集更详细地编辑了帖子。
猜你喜欢
  • 2013-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
相关资源
最近更新 更多