আমি কীভাবে দক্ষতার সাথে "অতি সাম্প্রতিকতম সারি" পেতে পারি?


53

আমার কাছে একটি ক্যোয়ারির ধরণ রয়েছে যা অবশ্যই খুব সাধারণ হতে পারে তবে এর জন্য কীভাবে দক্ষ ক্যোয়ারী লিখতে হয় তা আমি জানি না। আমি একটি সারণির সারিগুলি সন্ধান করতে চাই যা অন্য সারণির সারিগুলির সাথে "সবচেয়ে সাম্প্রতিক তারিখ নয়" অনুরূপ।

আমার একটি টেবিল আছে, inventoryবলুন, যা আমি নির্দিষ্ট দিনে ধরে রাখি এমন উপস্থাপনাগুলি উপস্থাপন করে।

date       | good | quantity
------------------------------
2013-08-09 | egg  | 5
2013-08-09 | pear | 7
2013-08-02 | egg  | 1
2013-08-02 | pear | 2

এবং একটি সারণী, "দাম" বলুন, যা নির্দিষ্ট দিনে একটি ভাল দাম রাখে

date       | good | price
--------------------------
2013-08-07 | egg  | 120
2013-08-06 | pear | 200
2013-08-01 | egg  | 110
2013-07-30 | pear | 220

আমি কীভাবে দক্ষতার সাথে ইনভেন্টরি টেবিলের প্রতিটি সারিটির "অতি সাম্প্রতিক" দাম পেতে পারি?

date       | pricing date | good | quantity | price
----------------------------------------------------
2013-08-09 | 2013-08-07   | egg  | 5        | 120
2013-08-09 | 2013-08-06   | pear | 7        | 200
2013-08-02 | 2013-08-01   | egg  | 1        | 110
2013-08-02 | 2013-07-30   | pear | 2        | 220

আমি এটি করার একটি উপায় জানি:

select inventory.date, max(price.date) as pricing_date, good
from inventory, price
where inventory.date >= price.date
and inventory.good = price.good
group by inventory.date, good

এবং তারপরে এই ক্যোয়ারিতে আবার যোগ করুন ইনভেন্টরিতে। বড় টেবিলের জন্য এমনকি প্রথম ক্যোয়ারী করা ( ইনভেন্টরিতে আবার যোগদান না করে) খুব ধীর। যাইহোক, যদি আমি ইনভেন্টরি টেবিল থেকে max(price.date) ... where price.date <= date_of_interest ... order by price.date desc limit 1প্রত্যেকের জন্য একটি করে ক্যোয়ারী ইস্যু করতে আমার প্রোগ্রামিংয়ের ভাষাটি ব্যবহার করি তবে একই সমস্যাটি দ্রুত সমাধান করা হয় date_of_interest, তাই আমি জানি যে কোনও গণনীয় প্রতিবন্ধকতা নেই। তবে আমি একটি একক এসকিউএল ক্যোয়ারীর সাহায্যে পুরো সমস্যাটি সমাধান করতে পছন্দ করব, কারণ এটি ক্যোয়ারির ফলাফলের ফলে আমাকে আরও এসকিউএল প্রসেসিং করার অনুমতি দেয়।

দক্ষতার সাথে এটি করার কোনও মানক উপায় নেই? এটি মনে হয় এটি প্রায়শই উঠে আসা উচিত এবং এটির জন্য একটি দ্রুত কোয়েরি লেখার একটি উপায় থাকা উচিত।

আমি পোস্টগ্র্রেস ব্যবহার করছি তবে একটি এসকিউএল-জেনেরিক উত্তর প্রশংসা করবে।


3
এটি দক্ষতার প্রশ্ন হিসাবে ডিবিএ.এসইতে স্থানান্তরিত হওয়ার পক্ষে ভোট দিয়েছে। আমরা কোয়েরিটি কয়েকটি ভিন্ন উপায়ে লিখতে পারি তবে এটি এটিকে আরও দ্রুত করতে পারে না।
ypercubeᵀᴹ

5
একটি একক জিজ্ঞাসা থেকে আপনার কি আসলে সমস্ত দিনের সমস্ত পণ্য দরকার? অসম্ভব প্রয়োজনের মতো মনে হচ্ছে? আরও সাধারণভাবে নির্দিষ্ট দামের জন্য নির্দিষ্ট দামের (নির্দিষ্ট তারিখে) মূল্য পুনরুদ্ধার করা যায়। এই বিকল্প প্রশ্নগুলি (উপযুক্ত) সূচকগুলি থেকে আরও সহজেই উপকৃত হতে পারে। আমাদের এটিও জানতে হবে: কার্ডিনালিটিস (প্রতিটি টেবিলের মধ্যে কত সারি?), সম্পূর্ণ টেবিল সংজ্ঞা সহ। ডেটা প্রকার, সীমাবদ্ধতা, সূচকগুলি, ... ( \d tblপিএসকিএল-এ ব্যবহার করুন ), আপনার পোস্টগ্রিসের সংস্করণ এবং কমপক্ষে। / সর্বাধিক ভাল প্রতি দাম সংখ্যা।
এরউইন ব্র্যান্ডস্টেটর

আপনি কি আমাকে উত্তর গ্রহণ করতে বলছেন? কোনটি সেরা তা জানার জন্য আমি সত্যিই যোগ্য নই, যদিও আপনার হিসাবে সবচেয়ে বেশি অগ্রাধিকার রয়েছে তাই আমি এটি গ্রহণ করে খুশি।
টম এলিস

কেবলমাত্র যদি তা আপনার প্রশ্নের উত্তর দেয় বা আপনার পক্ষে কাজ করে তবে তা গ্রহণ করুন। এমনকি যদি এটি সম্পর্কিত ক্ষেত্রে সহায়তা করতে পারে তবে আপনি কীভাবে এগিয়ে গিয়েছিলেন সে সম্পর্কে আপনি একটি মন্তব্যও রেখে যেতে পারেন। আপনি যদি মনে করেন আপনার প্রশ্নটি উত্তরহীন, তবে আমাদের জানান।
এরউইন ব্র্যান্ডস্টেটার

1
আমাকে তখন ক্ষমা চাইতে হবে, কারণ যদিও আমি উত্তর পেয়েছি যা উত্তম বলে মনে হয়েছে তবে আমি সেই সমস্যা নিয়ে কাজ করছি না যা প্রশ্ন উত্সাহিত করেছিল তাই আমি উত্তর দেওয়ার পক্ষে নেই যে সবচেয়ে ভাল উত্তর, বা যদি সত্যিই তাদের কোনও হয় তবে আমার ব্যবহারের ক্ষেত্রে এটি যেমন উপযুক্ত তেমন উপযুক্ত (যেমনটি ছিল)। এই ক্ষেত্রে আমার যদি কিছু ডিবিএ.স্ট্যাকেক্সচেঞ্জের প্রথা অনুসরণ করা উচিত তবে দয়া করে আমাকে জানান।
টম এলিস

উত্তর:


42

এটি পরিস্থিতি এবং সঠিক প্রয়োজনীয়তার উপর নির্ভর করে। প্রশ্নের আমার মন্তব্য বিবেচনা করুন ।

সহজ সমাধান

সঙ্গে DISTINCT ONPostgres মধ্যে:

SELECT DISTINCT ON (i.good, i.the_date)
       i.the_date, p.the_date AS pricing_date, i.good, p.price
FROM   inventory  i
LEFT   JOIN price p ON i.good = p.good AND i.the_date >= p.the_date
ORDER  BY i.good, i.the_date, p.the_date DESC;

আদেশ ফল।

বা NOT EXISTSস্ট্যান্ডার্ড এসকিউএল সহ (আমার পরিচিত প্রতিটি আরডিবিএমএসের সাথে কাজ করে):

SELECT i.the_date, p.the_date AS pricing_date, i.good, i.quantity, p.price
FROM   inventory  i
LEFT   JOIN price p ON p.good = i.good AND p.the_date <= i.the_date
WHERE  NOT EXISTS (
   SELECT 1 FROM price p1
   WHERE  p1.good = p.good
   AND p1.the_date <= i.the_date
   AND p1.the_date >  p.the_date
   );

একই ফলাফল, কিন্তু ব্যাপারে খেয়ালখুশীমত সাজানোর ক্রম - যদি না আপনি যোগ ORDER BY
ডেটা বিতরণ, সঠিক প্রয়োজনীয়তা এবং সূচকগুলির উপর নির্ভর করে এর যেগুলির একটিতে দ্রুততর হতে পারে।
সাধারণত, DISTINCT ONবিজয়ী এবং আপনি এটির উপরে একটি সাজানো ফলাফল পান। তবে নির্দিষ্ট কিছু ক্ষেত্রে অন্যান্য প্রশ্নের কৌশলগুলি (অনেক) দ্রুত, তবুও। নিচে দেখ.

সর্বোচ্চ / মিনিটের মানগুলি গণনা করতে সাবকিউরিয়াস সহ সমাধানগুলি সাধারণত ধীর হয়। সিটিই সহ ভেরিয়েন্টগুলি সাধারণত ধীর, তবুও।

সরল দর্শন (যেমনটি অন্য উত্তর দ্বারা প্রস্তাবিত) পোস্টগ্র্রেসের ক্ষেত্রে পারফরম্যান্সে মোটেই সহায়তা করে না।

এসকিউএল ফিডল।


সঠিক সমাধান

স্ট্রিং এবং কোলেশন

প্রথমত, আপনি একটি উপ-অনুকূল টেবিল বিন্যাস থেকে ভোগেন। এটি তুচ্ছ মনে হতে পারে তবে আপনার স্কিমাকে সাধারনকরণ করা আরও অনেক বেশি যেতে পারে।

চরিত্রের ধরণের অনুসারেtextvarchar বাছাই করা ( ,, ...) স্থানীয় অনুসারে করা উচিত - বিশেষত COLLATION । সম্ভবত আপনার ডিবি স্থানীয় নিয়মের কিছু সেট ব্যবহার করে (যেমন, আমার ক্ষেত্রে de_AT.UTF-8:)। এর সাথে সন্ধান করুন:

SHOW lc_collate;

এটি বাছাই এবং সূচক চেহারা আপকে ধীর করে তোলে । আপনার স্ট্রিংগুলি (পণ্যগুলির নাম) আরও খারাপ। আপনি যদি নিজের আউটপুটে (বা সাজানোর ক্রমটি মোটেই সাজিয়ে তোলেন) নিয়মের জন্য যত্নবান না হন তবে আপনি যুক্ত করলে এটি আরও দ্রুত হতে পারে COLLATE "C":

SELECT DISTINCT ON (i.good COLLATE "C", i.the_date)
       i.the_date, p.the_date AS pricing_date, i.good, p.price
FROM   inventory  i
LEFT   JOIN price p ON i.good = p.good AND i.the_date >= p.the_date
ORDER  BY i.good COLLATE "C", i.the_date, p.the_date DESC;

আমি কীভাবে দুটি স্থানে কোলেশন যুক্ত করেছি তা নোট করুন।
আমার পরীক্ষায় দু'বার দ্রুত 20 কে সারি এবং প্রতিটি মৌলিক নাম ('গুড 123') দিয়ে দ্বিগুণ

সূচক, সূচিপত্র

যদি আপনার ক্যোয়ারীটি একটি সূচক ব্যবহার করার কথা মনে করে, অক্ষর ডেটাযুক্ত কলামগুলিতে একটি ম্যাচিং কোলেশন ব্যবহার করতে হবে ( goodউদাহরণস্বরূপ):

CREATE INDEX inventory_good_date_desc_collate_c_idx
ON price(good COLLATE "C", the_date DESC);

এসও সম্পর্কিত এই সম্পর্কিত উত্তরের শেষ দুটি অধ্যায়টি পড়তে ভুলবেন না:

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

নিয়মমাফিক করা

অপ্রয়োজনীয় স্ট্রিং (ভাল নাম) আপনার টেবিলগুলি এবং সূচিগুলিও সবিস্তারে ফুটিয়ে তোলে যা সবকিছুকে আরও ধীর করে তোলে। সঠিক টেবিল বিন্যাসের সাহায্যে আপনি বেশিরভাগ সমস্যা শুরু করতে পারেন could এই মত দেখতে পারে:

CREATE TABLE good (
  good_id serial PRIMARY KEY
, good    text   NOT NULL
);

CREATE TABLE inventory (
  good_id  int  REFERENCES good (good_id)
, the_date date NOT NULL
, quantity int  NOT NULL
, PRIMARY KEY(good_id, the_date)
);

CREATE TABLE price (
  good_id  int     REFERENCES good (good_id)
, the_date date    NOT NULL
, price    numeric NOT NULL
, PRIMARY KEY(good_id, the_date));

প্রাথমিক কীগুলি আমাদের প্রয়োজনীয় সমস্ত সূচক স্বয়ংক্রিয়ভাবে সরবরাহ করে (প্রায়)।
অনুপস্থিত বিবরণ উপর নির্ভর করে, একটি multicolumn সূচক উপর priceদ্বিতীয় কলামে এ আদেশ সাজানো পারফরম্যান্সের উন্নতি করতে পারে:

CREATE INDEX price_good_date_desc_idx ON price(good, the_date DESC);

আবার কোলেশন অবশ্যই আপনার প্রশ্নের সাথে মেলে (উপরে দেখুন)।

পোস্টগ্রিস 9.2 বা তারপরে ইনডেক্স-কেবল স্ক্যানগুলির জন্য "কভারিং সূচকগুলি" আরও কিছুকে সহায়তা করতে পারে - বিশেষত যদি আপনার টেবিলগুলি অতিরিক্ত কলাম ধারণ করে, সারণিকে আচ্ছাদন সূচকের চেয়ে যথেষ্ট বড় করে তোলে।

এই ফলাফলগুলি আরও দ্রুত:

বিদ্যমান না

SELECT i.the_date, p.the_date AS pricing_date, g.good, i.quantity, p.price
FROM   inventory  i
JOIN   good       g USING (good_id)
LEFT   JOIN price p ON p.good_id = i.good_id AND p.the_date <= i.the_date
AND    NOT EXISTS (
   SELECT 1 FROM price p1
   WHERE  p1.good_id = p.good_id
   AND    p1.the_date <= i.the_date
   AND    p1.the_date >  p.the_date
   );

ডিস্টিন্ট চালু

SELECT DISTINCT ON (i.the_date)
       i.the_date, p.the_date AS pricing_date, g.good, i.quantity, p.price
FROM   inventory  i
JOIN   good       g USING (good_id)
LEFT   JOIN price p ON p.good_id = i.good_id AND p.the_date <= i.the_date
ORDER  BY i.the_date, p.the_date DESC;

এসকিউএল ফিডল।


দ্রুত সমাধান

যদি এখনও এটি পর্যাপ্ত দ্রুত না হয় তবে দ্রুত সমাধান হতে পারে।

পুনরাবৃত্তির সিটিই / JOIN LATERAL/ পারস্পরিক সম্পর্কযুক্ত সাবকোয়ারি

বিশেষত ভাল প্রতি অনেক দাম সহ ডেটা বিতরণের জন্য :

বস্তুগত দর্শন

আপনার যদি এটি প্রায়শই এবং দ্রুত চালানোর প্রয়োজন হয় তবে আমি আপনাকে একটি বস্তুগত দৃষ্টিভঙ্গি তৈরি করার পরামর্শ দিচ্ছি। আমি মনে করি এটি নিরাপদ বলে মনে করি, অতীতের তারিখগুলির জন্য মূল্য এবং জায়গুলি খুব কমই পরিবর্তিত হয়। ফলাফল একবার গণনা করুন এবং বস্তুগত দর্শন হিসাবে একটি স্ন্যাপশট সংরক্ষণ করুন।

পোস্টগ্রিজ 9.3+ পদার্থযুক্ত দর্শনগুলির জন্য স্বয়ংক্রিয় সমর্থন করেছে। আপনি পুরানো সংস্করণগুলিতে সহজেই একটি প্রাথমিক সংস্করণটি প্রয়োগ করতে পারেন।


3
আপনি যে price_good_date_desc_idxসূচকটি সুপারিশ করেছেন সেটি আমার একই অনুরোধের জন্য নাটকীয়ভাবে পারফরম্যান্সকে উন্নত করেছে। আমার ক্যোয়ারী পরিকল্পনাটি ব্যয় থেকে 42374.01..42374.86নেমে গেছে 0.00..37.12!
cimmanon

@ সিমনম্যান: চমৎকার! আপনার মূল ক্যোয়ারী বৈশিষ্ট্যটি কী? বিদ্যমান না? ডিস্টিন্ট অন? গ্রুপ দ্বারা?
এরউইন ব্র্যান্ডস্টেটার

DISTINCT ON ব্যবহার করুন
cimmanon

6

এফওয়াইআই, আমি এমএসকিউএল ২০০৮ ব্যবহার করেছি, সুতরাং পোস্টগ্র্যাসে "অন্তর্ভুক্ত" সূচক থাকবে না। তবে নীচে প্রদর্শিত বেসিক ইনডেক্সিং ব্যবহার করে হ্যাশ যোগ হয়ে পোস্টগ্র্রেসে যোগদানের জন্য পরিবর্তিত হবে: http://explain.depesz.com/s/eF6 (কোনও সূচি নয়) http://explain.depesz.com/s/j9x ( যোগদানের মানদণ্ডে সূচক সহ)

আমি আপনার জিজ্ঞাসাটি দুটি ভাগে বিভক্ত করার প্রস্তাব দিচ্ছি। প্রথমত, এমন একটি দৃশ্য (পারফরম্যান্স উন্নতির উদ্দেশ্যে নয়) যা বিভিন্ন প্রসঙ্গের মধ্যে ব্যবহার করা যেতে পারে যা জায়গুলির তারিখ এবং মূল্য নির্ধারণের তারিখের প্রতিনিধিত্ব করে।

create view mostrecent_pricing_dates_per_good as
select i.good,i.date i_date,max(p.date)p_date
  from inventory i
  join price p on i.good = p.good and i.date >= p.date
 group by i.good,i.date;

তারপরে তদন্ত (যেমন সাম্প্রতিক মূল্যের তারিখগুলি ছাড়াই জায় খুঁজে বের করতে বামে যোগ দিয়ে যোগ করা হয়েছে) যেমন আপনার জিজ্ঞাসাটি অন্য ধরণের জন্য ম্যানিপুলেট করা সহজ এবং সহজ হয়ে উঠতে পারে:

select i.good
       ,i.date inventory_date
       ,i.quantity
       ,p.date pricing_date
       ,p.price       
  from inventory i
  join price p on i.good = p.good
  join mostrecent_pricing_dates_per_good x 
    on i.good = x.good 
   and p.date = x.p_date
   and i.date = x.i_date

এটি নিম্নলিখিত সম্পাদন পরিকল্পনার ফল দেয়: http://sqlfiddle.com/#!3/24f23/1 কোন ইনডেক্সিং

... সম্পূর্ণ ধরণের সাথে সমস্ত স্ক্যান লক্ষ্য করুন হ্যাশ মিলগুলির পারফরম্যান্স ব্যয় মোট ব্যয়ের বেশিরভাগ অংশ নেয় ... এবং আমরা জানি যে টেবিল স্ক্যানগুলি এবং সাজানো ধীর (লক্ষ্যটির সাথে তুলনা করে: সূচী চাইছে)।

এখন, আপনার যোগদানের জন্য ব্যবহৃত মানদণ্ডগুলিকে সহায়তা করার জন্য বেসিক সূচকগুলি যুক্ত করুন (আমি দাবি করি না যে এগুলি সর্বোত্তম সূচী, তবে তারা বিষয়টি ব্যাখ্যা করে): http://sqlfiddle.com/#!3/5ec75/1 বেসিক ইনডেক্সিং সহ

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

চূড়ান্ত পুনরাবৃত্তিটি সূচকে "অন্তর্ভুক্ত" ব্যবহার করে পরিকল্পনার উপরের দিকে স্লাইড হওয়া এবং অতিরিক্তভাবে অনুরোধ করা ডেটা ঠিক সূচকের বাইরে থেকে পাওয়ার জন্য সহজ করে তোলে। সুতরাং অনুসন্ধানগুলি শেষ: http://sqlfiddle.com/#!3/5f143/1 1 এখানে চিত্র বর্ণনা লিখুন

এখন আমাদের কাছে একটি ক্যোয়ারী পরিকল্পনা রয়েছে যেখানে খুব দ্রুত সূচীকরণ ক্রিয়াকলাপগুলির মধ্যে ক্যোয়ারির মোট ব্যয় সমানভাবে ছড়িয়ে পড়ে। এটি যতটা ভাল পাবে ততই কাছাকাছি থাকবে। অবশ্যই অন্যান্য বিশেষজ্ঞরা এটিকে আরও উন্নত করতে পারে তবে সমাধানটি কয়েকটি বড় উদ্বেগকে সরিয়ে দেয়:

  1. এটি আপনার ডেটাবেজে স্বচ্ছ ডেটা স্ট্রাকচার তৈরি করে যা কোনও অ্যাপ্লিকেশনের অন্যান্য ক্ষেত্রে রচনা এবং পুনরায় ব্যবহার করা সহজ।
  2. সমস্ত ব্যয়বহুল ক্যোয়ারী অপারেটরগুলির মধ্যে কিছু বেসিক ইনডেক্সিং ব্যবহার করে ক্যোয়ারী পরিকল্পনা থেকে বেরিয়ে এসেছিল।

3
এটি দুর্দান্ত (এসকিউএল-সার্ভারের জন্য) তবে বিভিন্ন ডিবিএমএসের জন্য অনুকূলকরণের ক্ষেত্রে এর মিল রয়েছে, এর মধ্যে মারাত্মক পার্থক্য রয়েছে।
ypercubeᵀᴹ

@ টাইপকিউব এটি সত্য। পোস্টগ্রিস সম্পর্কে আমি কিছু যোগ্যতা যুক্ত করেছি। আমার উদ্দেশ্য ছিল যে এখানে চিত্রিত বেশিরভাগ চিন্তার প্রক্রিয়া DBMS নির্দিষ্ট বৈশিষ্ট্য নির্বিশেষে প্রয়োগ করবে।
কোকোগোরিলা

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

5

আপনার যদি পোস্টগ্রিজএসকিউএল 9.3 রয়েছে (আজ প্রকাশিত হয়েছে) তবে আপনি একটি সাম্প্রতিক যোগদান করতে পারেন।

আমার এটি পরীক্ষার কোনও উপায় নেই এবং এটি আগে কখনও ব্যবহার করি নি, তবে ডকুমেন্টেশন থেকে আমি যা বলতে পারি তা থেকে সিনট্যাক্সটি এমন হবে:

SELECT  Inventory.Date,
        Inventory.Good,
        Inventory.Quantity,
        Price.Date,
        Price.Price
FROM    Inventory
        LATERAL
        (   SELECT  Date, Price
            FROM    Price
            WHERE   Price.Good = Inventory.Good
            AND     Price.Date <= Inventory.Date
            ORDER BY Price.Date DESC
            LIMIT 1
        ) p;

এটি মূলত এসকিউএল-সার্ভারের অ্যাপ্লাই এর সমতুল্য এবং ডেমো উদ্দেশ্যে এসকিউএল-ফিডেলে এর কার্যকরী উদাহরণ রয়েছে


5

এরউইন এবং অন্যরা যেমন উল্লেখ করেছেন, একটি দক্ষ ক্যোয়ারী প্রচুর ভেরিয়েবলের উপর নির্ভর করে এবং পোস্টগ্রেএসকিউএল সেই ভেরিয়েবলগুলির উপর ভিত্তি করে কোয়েরি এক্সিকিউশনটি অনুকূল করতে খুব চেষ্টা করে। সাধারণভাবে আপনি প্রথমে স্বচ্ছতার জন্য লিখতে চান এবং তারপরে বাধা চিহ্নিত করার পরে কার্য সম্পাদনের জন্য পরিবর্তন করতে চান ।

অতিরিক্তভাবে পোস্টগ্র্যাসকিউএল-তে প্রচুর কৌশল রয়েছে যা আপনি জিনিসকে কিছুটা দক্ষ করে তুলতে পারেন (একের জন্য আংশিক সূচকগুলি) সুতরাং আপনার পড়ার / লেখার বোঝার উপর নির্ভর করে আপনি খুব যত্ন সহকারে ইনডেক্সিংয়ের দিকে নজর রেখে এটিকে আরও অনুকূল করতে পারবেন।

প্রথমে চেষ্টা করার চেষ্টাটি হল কেবল একটি দৃশ্য করা এবং এতে যোগদান করা:

CREATE VIEW most_recent_rows AS
SELECT good, max(date) as max_date
FROM inventory
GROUP BY good;

এর মতো কিছু করার সময় এটি ভাল সম্পাদন করা উচিত:

SELECT price 
  FROM inventory i
  JOIN goods g ON i.goods = g.description
  JOIN most_recent_rows r ON i.goods = r.goods
 WHERE g.id = 123;

তারপরে আপনি এতে যোগ দিতে পারেন। কোয়েরিটি অন্তর্নিহিত সারণীর বিপরীতে ভিউটিতে যোগদান করবে, তবে ধরে নেওয়া আপনার অনন্য সূচক রয়েছে (তারিখ, সেই ক্রমে ভাল ), আপনাকে যেতে হবে (যেহেতু এটি একটি সাধারণ ক্যাশে অনুসন্ধান হবে)। কয়েক সারি সন্ধান করা এটি খুব ভালভাবে কাজ করবে তবে আপনি যদি লক্ষ লক্ষ পণ্যের দাম হজমের চেষ্টা করছেন তবে খুব অদক্ষ হয়ে উঠবে।

দ্বিতীয় জিনিসটি আপনি যা করতে পারেন তা হ'ল জায় তালিকাতে সর্বাধিক_আরসেন্ট বুল কলাম এবং

create unique index on inventory (good) where most_recent;

এর পরে আপনি যখন কোনও ভালর জন্য একটি নতুন সারি wasোকানো হয় তখন মোস্ট_সেন্টকে মিথ্যা হিসাবে সেট করতে ট্রিগারগুলি ব্যবহার করতে চান। এটি বাগের জন্য আরও জটিলতা এবং আরও বেশি সম্ভাবনা যুক্ত করে তবে এটি সহায়ক।

আবার এটির অনেকগুলি নির্ভর করে যথাযথ সূচকগুলি স্থানে রয়েছে। সর্বাধিক সাম্প্রতিক তারিখের প্রশ্নের জন্য, আপনার সম্ভবত তারিখে সূচি থাকতে হবে এবং একটি বহু-কলামের তারিখ দিয়ে শুরু হওয়া এবং আপনার যোগদানের মানদণ্ড সহ including

পিছু নীচে এরউইনের মন্তব্য আপডেট করুন, দেখে মনে হচ্ছে আমি এটি ভুল বুঝেছি। প্রশ্নটি পুনরায় পড়ার পরে আমি কী জিজ্ঞাসা করছি তা নিশ্চিত নই। আমি আপডেটে উল্লেখ করতে চাই যে আমি দেখছি যে সম্ভাব্য সমস্যা এবং এটি কেন এই অস্পষ্ট ছেড়ে যায়।

অফার করা ডেটাবেস ডিজাইনের ERP এবং অ্যাকাউন্টিং সিস্টেমগুলির সাথে সত্যিকারের ব্যবহারের IME নেই। এটি একটি অনুমানের নিখুঁত মূল্য নির্ধারণের মডেলটিতে কাজ করবে যেখানে কোনও প্রদত্ত পণ্যের প্রদত্ত দিনে বিক্রি করা সমস্ত জিনিসের দাম একই থাকে। যাইহোক, এই সবসময় তা হয় না. মুদ্রা এক্সচেঞ্জের মতো জিনিসগুলির ক্ষেত্রে এটি এমনকি হয় না (যদিও কিছু মডেল ভান করে যে এটি করে)। এটি যদি স্বীকৃত উদাহরণ হয় তবে এটি অস্পষ্ট। এটি যদি আসল উদাহরণ হয় তবে ডেটা স্তরে ডিজাইনে আরও বড় সমস্যা রয়েছে। আমি এখানে ধরে নিতে চলেছি যে এটি একটি আসল উদাহরণ।

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

 SELECT price 
   FROM prices p
   JOIN goods g ON p.good = g.good
  WHERE g.id = 123 AND p."date" >= '2013-03-01'
  ORDER BY p."date" ASC LIMIT 1;

দামের সূচক (ভাল, তারিখ) সহ এটি ভাল সম্পাদন করবে।

আমি এটি একটি স্বীকৃত উদাহরণ, সম্ভবত আপনি যা কাজ করছেন তার কাছাকাছি কিছু সাহায্য করবে।


most_recentপদ্ধতির সাম্প্রতিকতম মূল্য জন্য ভাল কাজ করা উচিত একেবারে । এটি দেখে মনে হবে যে ওপিকে প্রতিটি ইনভেন্টরি তারিখের তুলনায় সাম্প্রতিকতম দামের প্রয়োজন ।
এরউইন ব্র্যান্ডসেটেটার

ভাল যুক্তি. পুনরায় পড়া যদিও আমি প্রস্তাবিত ডেটা সহ কিছু বাস্তব ব্যবহারিক ঘাটতি চিহ্নিত করেছি তবে আমি এটি বলতে পারি না এটি কেবল একটি স্বীকৃত উদাহরণ কিনা। একটি স্বীকৃত উদাহরণ হিসাবে, আমি কী অনুপস্থিত তা বলতে পারছি না। সম্ভবত এটি আপডেট করার জন্য একটি আপডেটও ক্রমযুক্ত হবে।
ক্রিস ট্র্যাভারস

@ ক্রিসট্রেভারস: এটি একটি স্বীকৃত উদাহরণ, তবে আমি যে প্রকৃত স্কিমা নিয়ে কাজ করছি তা পোস্ট করার মতো স্বাধীনতা আমার নেই। আপনি যে ব্যবহারিক ঘাটতিগুলি চিহ্নিত করেছেন তা সম্পর্কে আপনি সম্ভবত কিছুটা বলতে পারেন।
টম এলিস

আমি মনে করি এটি সঠিক হওয়া দরকার, তবে রূপকথায় সমস্যাটি হারিয়ে যাওয়ার বিষয়ে উদ্বিগ্ন। কিছুটা কাছে গেলে সহায়ক হবে। সমস্যাটি হচ্ছে দাম নির্ধারণের সাথে, নির্দিষ্ট দিনে দামটি সম্ভবত একটি ডিফল্ট হতে পারে এবং ফলস্বরূপ আপনি কেবল এটি লেনদেনের প্রবেশের জন্য একটি ডিফল্ট হিসাবে রিপোর্ট করার জন্য ব্যবহার করবেন না, সুতরাং আপনার আকর্ষণীয় প্রশ্নগুলি সাধারণত একটিতে কয়েকটি সারি হয় সময়।
ক্রিস ট্র্যাভারস

3

অন্য উপায়টি হ'ল lead()সারণির দামের প্রতিটি সারিটির জন্য তারিখের সীমা পেতে উইন্ডো ফাংশনটি ব্যবহার করা এবং তারপরে betweenইনভেন্টরিতে যোগদানের সময় ব্যবহার করা । আমি বাস্তবে এটি বাস্তব জীবনে ব্যবহার করেছি, তবে মূলত কারণ এটি কীভাবে সমাধান করা যায় এটি আমার প্রথম ধারণা ছিল।

with cte as (
  select
    good,
    price,
    date,
    coalesce(lead(date) over(partition by good order by date) - 1
            ,Now()::date) as ndate
  from
    price
)

select * from inventory i join cte on
  (i.good = cte.good and i.date between cte.date and cte.ndate)

SqlFiddle


1

সংস্থার সাথে জড়িত শর্তগুলির সাথে জায়ের সাথে দামের যোগ ব্যবহার করুন যা দামের টেবিলপ থেকে রেকর্ডগুলি কেবলমাত্র জায়ের তারিখের আগে বা তার আগে সীমাবদ্ধ করে, তারপরে সর্বাধিক তারিখটি বের করুন এবং সেই উপসেট থেকে যে তারিখটি সর্বোচ্চ তারিখ হবে

সুতরাং আপনার জায় মূল্য জন্য:

 Select i.date, p.Date pricingDate,
    i.good, quantity, price        
 from inventory I join price p 
    on p.good = i.good
        And p.Date = 
           (Select Max(Date from price
            where good = i.good
               and date <= i.Date)

যদি কোনও নির্দিষ্ট ভালের জন্য দাম একই দিনে একবারের বেশি পরিবর্তিত হয় এবং আপনার কাছে কেবল তারিখ থাকে এবং এই কলামগুলিতে কোনও সময় না পাওয়া যায় তবে দাম পরিবর্তনের রেকর্ডগুলির মধ্যে একটি বেছে নিতে আপনাকে যোগ দিতে আরও বিধিনিষেধ প্রয়োগ করতে হবে।


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