Postgresql

不同的查詢導致性能差異很大

  • May 20, 2013

我有 2 個類似的功能,不同的方式導致性能差異很大。

PostgreSQL 版本:9.2.1。

功能一

create or replace function func_1()  returns text  as
$$
declare
  v_i integer;  
  v_md5 varchar; 
begin
  for v_i in 1..1000000 loop
      v_md5:='a'|| v_i::character varying;
  end loop;  
  return 'ok';
end;
$$
language plpgsql;

功能二

create or replace function func_select()  returns text  as
$$
declare
  v_i integer;  
  v_md5 varchar; 
begin
  for v_i in 1..1000000 loop
     select 'a'|| v_i::character varying into  v_md5;
  end loop;
  return 'ok';
end;
$$
language plpgsql;

功能時序

francs=> \timing
Timing is on.
francs=> select func_1();
func_1 
--------
ok
(1 row)

Time: 1467.231 ms
francs=> select func_1();
func_1 
--------
ok
(1 row)

Time: 1383.424 ms
francs=> select func_select();
func_select 
-------------
ok
(1 row)

Time: 22176.600 ms
francs=> select func_select();
func_select 
-------------
ok
(1 row)

Time: 23265.755 ms

從上面看,函式func_1()只需要大約1383 毫秒,但函式func_select()大約需要 23265 毫秒,有人能解釋一下嗎?

在第二個循環中使用純 SQL 語句使數據庫引擎在每次循環迭代之前**編譯整個循環,然後對其進行評估,而變數賦值則很容易解析為低級指令一次。select 'a'|| v_i::character varying into v_md5;

為了獲得最佳性能,您可能會generate_series使用

create or replace function func_1()  returns text  as
$$
declare
 v_i integer;  
 v_md5 varchar; 
 begin
    select 'a'||i     into  v_md5
    from generate_series(1, 1000000) i;
    return 'ok';
 end;
$$
language plpgsql;

在我的測試中,它需要你第一次實現時間的1/6 。

附錄: 順便說一句,這三種實現之間的主要區別在於您在一條指令中將多少工作委派給後端。在我的解決方案中,您沒有循環,因此它是 1 條指令,而在您的第二個實現中,您有一個包含 select 的循環(這是一個複雜的函式),而在您的第一個範例中,您有一個包含賦值的循環(即是一個簡單的函式)。這解釋了差異。

引用自:https://dba.stackexchange.com/questions/40422