1. 为什么要使用pl/lua

pl/lua是一个插件,可以使用lua语言写PostgreSQL的存储过程和函数,使用lua语言有如下几个好处,

  • 可以大大提升存储过程的性能,特别是循环的性能。
  • 在PostgreSQL中数组或一些json对象都是不可变的,如往数组或json对象中添加元素时,需要把拷贝源对象而生成一个新对象,导致很大的开销。而使用lua语言的list和table对象就没有这个问题了。
  • lua语言的语法更灵活。

也就是当我们需要在存储过程或函数中做一些密集的运算,使用plpgsql会比较慢,而使用pl/lua会提升10倍以上的性能。这个提升还是很观的,所以建议这些存储过程使用pllua来编写。

2. 我们先看看性能

2.1 查看循环的效率

我们分别使用pllua和pgplsql建两个循环的函数:

  1. create or replace function f_pl01(cnt int) returns int language plpgsql as $$
  2. declare
  3. i int;
  4. begin
  5. i:=0;
  6. LOOP
  7. i = i + 1;
  8. EXIT WHEN i >= cnt;
  9. END LOOP;
  10. return i;
  11. end;
  12. $$;
  1. create function f_lua01(cnt int) returns int language pllua as $$
  2. local i=0
  3. while( i < cnt ) do
  4. i = i+1
  5. end
  6. return i
  7. $$;

运行一下看执行时间:

  1. postgres=# \timing
  2. Timing is on.
  3. postgres=# select f_pl01(10000000);
  4. f_pl01
  5. ----------
  6. 10000000
  7. (1 row)
  8. Time: 6482.846 ms (00:06.483)
  9. postgres=# select f_lua01(10000000);
  10. f_lua01
  11. ----------
  12. 10000000
  13. (1 row)
  14. Time: 556.831 ms

可以看出使用pgplsql循环1千万次,需要6秒多,而使用pllua只需要557毫秒,快了近12倍。

如果我们建一个plpython的函数,如下所示:

  1. create or replace function f_py01(cnt int) returns int language plpython3u as $$
  2. i = 0
  3. while i < cnt:
  4. i = i + 1
  5. return i
  6. $$;

看一下执行时间:

  1. postgres=# select f_py01(10000000);
  2. f_py01
  3. ----------
  4. 10000000
  5. (1 row)
  6. Time: 1008.750 ms (00:01.009)

可以看出使用python是1秒中,也比plpgsql快很多。

2.2 数组中添加元素中的效率

我们再建两个存储过程,

  1. create or replace function f_pl02(cnt int) returns int language plpgsql as $$
  2. declare
  3. i int;
  4. myarr text[];
  5. s1 text;
  6. begin
  7. i:=0;
  8. s1 := lpad('', 2048, 'helloosdba');
  9. LOOP
  10. myarr := array_append(myarr, s1);
  11. i = i + 1;
  12. EXIT WHEN i >= cnt;
  13. END LOOP;
  14. return array_length(myarr, 1);
  15. end;
  16. $$;
  1. create or replace function f_lua02(cnt int) returns int language pllua as $$
  2. local i=0
  3. local myarr = {}
  4. local s1 = string.rep('helloosdba', 2048)
  5. while( i < cnt ) do
  6. i = i+1
  7. myarr[i] = s1
  8. end
  9. return #myarr
  10. $$;
  1. postgres=# select f_pl02(100000);
  2. f_pl02
  3. --------
  4. 100000
  5. (1 row)
  6. Time: 756.772 ms
  7. postgres=# select f_lua02(100000);
  8. f_lua02
  9. ---------
  10. 100000
  11. (1 row)
  12. Time: 10.731 ms

可以看到差了70多倍。这是因为使用plpgsql是,每次改变数组都需要把源数组复制一次,当数组越来越大时,每复制一次会花很长的时间。

如果是plpython:

  1. create or replace function f_py02(cnt int) returns int language plpython3u as $$
  2. i = 0
  3. myarr = []
  4. s1 = 'helloosdba'*2048
  5. while i < cnt:
  6. i = i+1
  7. myarr.append(s1)
  8. return len(myarr)
  9. $$;

执行时间:

  1. postgres=# select f_py02(100000);
  2. f_py02
  3. --------
  4. 100000
  5. (1 row)
  6. Time: 23.459 ms

plpython也比较快,不过比pllua慢一倍。

3. 安装方法

安装pllua之前需要先安装lua5.3.5,到网站上http://www.lua.org/download.html 下载lua5.3.5,然后编译安装:

  1. cd /usr/src
  2. curl -R -O http://www.lua.org/ftp/lua-5.3.5.tar.gz
  3. tar xvf lua-5.3.5.tar.gz

默认的编译出来的lua再编译选项中没有加“-fPIC”,会导致我们后面编译pllua时报错:

  1. /usr/bin/ld: /usr/local/lib/liblua.a(loadlib.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
  2. /usr/bin/ld: final link failed: Nonrepresentable section on output
  3. collect2: error: ld returned 1 exit status

到目录cd lua-5.3.5/src下,修改Makefile,在CFLAGS中增加-fPIC

  1. CFLAGS= -fPIC -O2 -Wall -Wextra -DLUA_COMPAT_5_2 $(SYSCFLAGS) $(MYCFLAGS)

然后再编译和安装lua:

  1. make install

编译安装pllua:

  1. cd /usr/src
  2. git clone https://github.com/pllua/pllua-ng.git
  3. cd pllua-ng
  4. make PG_CONFIG=/usr/pgsql-11/bin/pg_config
  5. make PG_CONFIG=/usr/pgsql-11/bin/pg_config install

然后在数据库中就可以加载pllua插件了:

  1. create extension pllua;

4. pl/lua的一些资料

0 评论  
添加一条新评论