在 PostgreSQL 中提取拆分字符串的最后一部分的最有效方法是啥?

Posted

技术标签:

【中文标题】在 PostgreSQL 中提取拆分字符串的最后一部分的最有效方法是啥?【英文标题】:What is the most efficient way to extract the last part of a split string in PostgreSQL?在 PostgreSQL 中提取拆分字符串的最后一部分的最有效方法是什么? 【发布时间】:2020-10-13 14:11:02 【问题描述】:

我想在 PostgreSQL 函数中将完全限定域的子域提取到第二级。

目前我有以下可用的 sn-p,但我不确定这是否是最有效的方法:

subdomains := left(query, length(query) - length(tld));
RETURN reverse(split_part(reverse(subdomains), '.', 1)) || tld;

保证querytld 子字符串结尾。

例子:

+---------------------+---------+---------------+
|        query        |   tld   |    output     |
+---------------------+---------+---------------+
| abc.example.com     | .com    | example.com   |
| x.y.z.example.co.uk | .co.uk  | example.co.uk |
| zzz.123.yyy.com.br  | .com.br | yyy.com.br    |
+---------------------+---------+---------------+

【问题讨论】:

【参考方案1】:

这个效率也不是特别高,但至少没有两次reverse,我猜array_length 很便宜,string_to_array 大致和split_part 一样贵。这可能是错误的,但值得一试。

sd_arr := string_to_array(subdomains, '.');
RETURN sd_arr[array_length(sd_arr , 1)] || tld;

没有变量赋值会更好:

RETURN (select arr[array_length(arr,1)] from (select string_to_array(subdomains, '.') as arr) t) || tld; 

【讨论】:

有趣的是,与此同时,我几乎自己创建了完全相同的替代方案,它具有性能优势,但不幸的是不到 1% :(【参考方案2】:

不确定这是否更有效,但您可以将其与您的实现进行比较:

create or replace function get_domain(p_input text, p_tld text)
  returns text
as
$$
declare
  l_tld text[];
  l_items text[];
begin 
  l_tld := string_to_array(trim('.' from p_tld), '.');
  l_items := string_to_array(trim('.' from p_input), '.');
  return array_to_string(l_items[cardinality(l_items) - cardinality(l_tld):], '.'); 
end
$$
language plpgsql
immutable;

它本质上将输入和***域转换为数组(剥离任何前导 . 以避免空数组元素。

然后它通过从输入的长度中减去 tld 的长度(=元素的数量)来计算要返回的起始元素。因此,对于输入 x.y.z.example.co.uk,这是 6 - 2,这意味着它返回从第 4 个元素开始的所有内容,然后将其转换回“点”表示法。

Online example

【讨论】:

以上是关于在 PostgreSQL 中提取拆分字符串的最后一部分的最有效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中拆分点上的字符串并从中提取所有字段?

PostgreSQL 9.3:拆分给定字符串

查找字符串中最后一次出现的数字,并按该值拆分字符串

在某个字符的最后一次出现处拆分字符串

在postgresql中将值提取到逗号分隔的字符串中[重复]

postgresql:从文本中自动提取字符串