নির্বাচন এবং WHERE ধারাতে একই ফাংশন


11

প্রাথমিক প্রশ্ন:

f(x, y)আমার ডাটাবেস টেবিলের দুটি কলামে x এবং y এর ব্যয়বহুল ফাংশন আমার আছে ।

আমি একটি ক্যোয়ারী কার্যকর করতে চাই যা আমাকে কলাম হিসাবে ফাংশনটির ফলাফল দেয় এবং তাতে বাধা দেয়, এরকম কিছু

SELECT *, f(x, y) AS func FROM table_name WHERE func < 10;

তবে এটি কাজ করে না, তাই আমাকে এরকম কিছু লিখতে হবে

SELECT *, f(x, y) AS func FROM table_name WHERE f(x, y) < 10;

এটি কি ব্যয়বহুল ফাংশনটি দু'বার চালাবে? এটি করার সর্বোত্তম উপায় কী?


1
কাজটি STABLE/ IMMUTABLEবা VOLATILE?
ইভান ক্যারল

উত্তর:


22

আসুন এমন একটি ফাংশন তৈরি করুন যার পার্শ্ব প্রতিক্রিয়া রয়েছে যাতে আমরা দেখতে পাই যে এটি কতবার সম্পাদিত হয়:

CREATE OR REPLACE FUNCTION test.this_here(val integer)
    RETURNS numeric
    LANGUAGE plpgsql
AS $function$
BEGIN
    RAISE WARNING 'I am called with %', val;
    RETURN sqrt(val);
END;
$function$;

এবং তারপরে আপনার মতো করে কল করুন:

SELECT this_here(i) FROM generate_series(1,10) AS t(i) WHERE this_here(i) < 2;

WARNING:  I am called with 1
WARNING:  I am called with 1
WARNING:  I am called with 2
WARNING:  I am called with 2
WARNING:  I am called with 3
WARNING:  I am called with 3
WARNING:  I am called with 4
WARNING:  I am called with 5
WARNING:  I am called with 6
WARNING:  I am called with 7
WARNING:  I am called with 8
WARNING:  I am called with 9
WARNING:  I am called with 10
    this_here     
──────────────────
                1
  1.4142135623731
 1.73205080756888
(3 rows)

আপনি দেখতে পাচ্ছেন, ফাংশনটি কমপক্ষে একবার কল করা হয় ( WHEREক্লজ থেকে ), এবং শর্তটি সত্য হলে, আরও একবার আউটপুট উত্পাদন করতে।

দ্বিতীয় মৃত্যুদণ্ড এড়াতে, আপনি এডগার এর পরামর্শ অনুযায়ী যা করতে পারেন - যথা কোয়েরিটি মোড়ানো এবং ফলাফল সেটটি ফিল্টার করুন:

SELECT * 
  FROM (SELECT this_here(i) AS val FROM generate_series(1,10) AS t(i)) x 
 WHERE x.val < 2;

WARNING:  I am called with 1
... every value only once ...
WARNING:  I am called with 10

এটি কীভাবে কাজ করে তা পরীক্ষা করার জন্য, কেউ সেখানে গিয়ে pg_stat_user_functionsচেক করতে পারে calls(প্রদত্ত সমস্ত track_functionsকিছু সেট করা আছে)।

আসুন এমন কিছু দিয়ে চেষ্টা করুন যার কোনও পার্শ্ব প্রতিক্রিয়া নেই:

CREATE OR REPLACE FUNCTION test.simple(val numeric)
 RETURNS numeric
 LANGUAGE sql
AS $function$
SELECT sqrt(val);
$function$;

SELECT simple(i) AS v 
  FROM generate_series(1,10) AS t(i)
 WHERE simple(i) < 2;
-- output omitted

SELECT * FROM pg_stat_user_functions WHERE funcname = 'simple';
-- 0 rows

simple()তাই এটি করা যেতে পারে আসলে খুব সহজ inlined , সুতরাং এটি দৃশ্য মনে হচ্ছে না। আসুন এটি অন-অন্তর্ভুক্তযোগ্য:

CREATE OR REPLACE FUNCTION test.other_one(val numeric)
 RETURNS numeric
 LANGUAGE sql
AS $function$
SELECT 1; -- to prevent inlining
SELECT sqrt(val);
$function$;

SELECT other_one(i) AS v
  FROM generate_series(1,10) AS t(i)
 WHERE other_one(i) < 2;

SELECT * FROM pg_stat_user_functions ;
 funcid  schemaname  funcname   calls  total_time  self_time 
────────┼────────────┼───────────┼───────┼────────────┼───────────
 124311  test        other_one     13       0.218      0.218

SELECT *
  FROM (SELECT other_one(i) AS v FROM generate_series(1,10) AS t(i)) x 
 WHERE v < 2;

SELECT * FROM pg_stat_user_functions ;
 funcid  schemaname  funcname   calls  total_time  self_time 
────────┼────────────┼───────────┼───────┼────────────┼───────────
 124311  test        other_one     23       0.293      0.293

যেমনটি দেখা যাচ্ছে, ছবিটি পাশাপাশি বা পার্শ্ব প্রতিক্রিয়া ছাড়াই একই।

পরিবর্তন other_one()করার জন্য IMMUTABLE, পরিবর্তন আচরণ (হয়তো এটি আশ্চর্যজনক) খারাপ হিসেবে এটি উভয় ক্যোয়ারিগুলিতে 13 বার ডাকা হবে।


ফাংশনটির শরীরে কোনও পার্শ্ব-প্রতিক্রিয়াশীল নির্দেশের উপস্থিতি দ্বারা ফাংশনটি আবার কল করার সিদ্ধান্তটি কি স্থির করা যেতে পারে? একই পরামিতি (গুলি) সহ কোনও ক্রিয়াকলাপটি একবারে বা একাধিকবার ক্যোয়ারী প্ল্যানটি দেখে (যদি উদাহরণস্বরূপ, এর কোনও পার্শ্ব-প্রতিক্রিয়াযুক্ত অংশ না থাকে) সন্ধান করা সম্ভব কিনা?
অ্যান্ড্রি এম

@ অ্যান্ড্রিএম আমি হ্যাঁ কল্পনা করতে পারি, তবে আসলে কী বলা হয় তা দেখার জন্য বর্তমানে কোনও ডিবাগারের সাথে খেলার সময় নেই। অন্তর্ভুক্ত ফাংশনগুলি সম্পর্কে কিছুটা যুক্ত করবে (যা ওপি আশা করবে এমনটি নয়, যেমনটি এটি শোনাচ্ছে)।
dezso

1
@ অ্যান্ড্রিএম, পোস্ট অনুসারে: postgresql.org/docs/9.1/static/sql-createfunction.html একটি ফাংশন ভোল্যাটাইল বলে মনে করা হয় যদি তা অপ্রয়োজনীয় বা স্ট্যাবল হিসাবে ঘোষণা না করা হয়। ভোলিটাইল ইঙ্গিত দেয় যে ফাংশনের মান একটি একক টেবিল স্ক্যানের মধ্যেও পরিবর্তিত হতে পারে, সুতরাং কোনও অপ্টিমাইজেশন করা যায় না।
লেনার্ট

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.