পরিসরের ধরণের যথাযথ সাম্যতার কারণে খারাপ কোয়েরি পরিকল্পনা কীভাবে পরিচালনা করবেন?


28

আমি একটি আপডেট করছি যেখানে আমার একটি tstzrangeভেরিয়েবলের সাথে সঠিক সাম্য প্রয়োজন । M 1 এম সারিগুলি সংশোধন করা হয়েছে, এবং ক্যোয়ারীতে 13 মিনিট সময় লাগে। ফলাফল এখানেEXPLAIN ANALYZE দেখা যায় , এবং প্রকৃত ফলাফল ক্যোয়ার পরিকল্পনাকারী দ্বারা অনুমান করা থেকে পৃথক। সমস্যাটি হ'ল সূচক স্ক্যানটি প্রত্যাশা করে যে কোনও একক সারি ফিরে আসবে।t_range

এটি এই সত্যের সাথে সম্পর্কিত বলে মনে হয় যে পরিসরের ধরণের পরিসংখ্যানগুলি অন্য ধরণের তুলনায় আলাদাভাবে সংরক্ষণ করা হয়। এ খুঁজছি pg_statsকলামের জন্য দেখুন, n_distinct-1 এবং অন্যান্য ক্ষেত্র (যেমন most_common_vals, most_common_freqs) খালি আছে।

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

এর বিতরণ t_rangeকিছুটা অস্বাভাবিক। আমি অন্য টেবিলের tableতিহাসিক অবস্থা সংরক্ষণ করতে এই টেবিলটি ব্যবহার করছি এবং অন্য টেবিলের পরিবর্তনগুলি একবারে বড় আকারের ডাম্পগুলিতে ঘটে, তাই এর আলাদা আলাদা মানগুলি হয় না t_range। এখানে প্রতিটি অনন্য মানের সাথে সম্পর্কিত গণনা রয়েছে t_range:

                              t_range                              |  count  
-------------------------------------------------------------------+---------
 ["2014-06-12 20:58:21.447478+00","2014-06-27 07:00:00+00")        |  994676
 ["2014-06-12 20:58:21.447478+00","2014-08-01 01:22:14.621887+00") |   36791
 ["2014-06-27 07:00:00+00","2014-08-01 07:00:01+00")               | 1000403
 ["2014-06-27 07:00:00+00",infinity)                               |   36791
 ["2014-08-01 07:00:01+00",infinity)                               |  999753

t_rangeউপরের স্বতন্ত্র গণনাগুলি সম্পূর্ণ, সুতরাং কার্ডিনালটি M 3 এম (যার মধ্যে update 1M আপডেটের কোয়েরিতে প্রভাবিত হবে)।

ক্যোয়ারী 1 কেন 2 এর চেয়ে বেশি খারাপভাবে সম্পাদন করে? আমার ক্ষেত্রে, ক্যোয়ারি 2 একটি ভাল বিকল্প, তবে যদি সত্যিকারের সীমার সাম্যতা প্রয়োজন হয় তবে আমি কীভাবে পোস্টগ্রেসকে আরও চৌকস ক্যোয়ারী প্ল্যান ব্যবহার করতে পারি?

সূচিপত্র সহ সারণির সংজ্ঞা (অপ্রাসঙ্গিক কলামগুলি বাদ দেওয়া):

       Column        |   Type    |                                  Modifiers                                   
---------------------+-----------+------------------------------------------------------------------------------
 history_id          | integer   | not null default nextval('gtfs_stop_times_history_history_id_seq'::regclass)
 t_range             | tstzrange | not null
 trip_id             | text      | not null
 stop_sequence       | integer   | not null
 shape_dist_traveled | real      | 
Indexes:
    "gtfs_stop_times_history_pkey" PRIMARY KEY, btree (history_id)
    "gtfs_stop_times_history_t_range" gist (t_range)
    "gtfs_stop_times_history_trip_id" btree (trip_id)

প্রশ্ন 1:

UPDATE gtfs_stop_times_history sth
SET shape_dist_traveled = tt.shape_dist_traveled
FROM gtfs_stop_times_temp tt
WHERE sth.trip_id = tt.trip_id
AND sth.stop_sequence = tt.stop_sequence
AND sth.t_range = '["2014-08-01 07:00:01+00",infinity)'::tstzrange;

প্রশ্ন 2:

UPDATE gtfs_stop_times_history sth
SET shape_dist_traveled = tt.shape_dist_traveled
FROM gtfs_stop_times_temp tt
WHERE sth.trip_id = tt.trip_id
AND sth.stop_sequence = tt.stop_sequence
AND '2014-08-01 07:00:01+00'::timestamptz <@ sth.t_range;

কিউ 1 আপডেট 999753 সারি এবং কিউ 2 আপডেট 999753 + 36791 = 1036544 (অর্থাত টেম্প টেবিলটি এমন যে সময় সীমা শর্তের সাথে মিলিয়ে প্রতিটি সারি আপডেট করা হয়)।

@ ইয়পারক्यूबের মন্তব্যের জবাবে আমি এই প্রশ্নের চেষ্টা করেছি :

প্রশ্ন 3:

UPDATE gtfs_stop_times_history sth
SET shape_dist_traveled = tt.shape_dist_traveled
FROM gtfs_stop_times_temp tt
WHERE sth.trip_id = tt.trip_id
AND sth.stop_sequence = tt.stop_sequence
AND sth.t_range <@ '["2014-08-01 07:00:01+00",infinity)'::tstzrange
AND '["2014-08-01 07:00:01+00",infinity)'::tstzrange <@ sth.t_range;

ক্যোয়ারী পরিকল্পনা এবং ফলাফলগুলি ( এখানে দেখুন ) পূর্ববর্তী দুটি ক্ষেত্রে (~ 6 মিনিট) মধ্যবর্তী ছিল।

2016/02/05 সম্পাদনা

1.5 বছর পরে ডেটাতে আর অ্যাক্সেস নেই, আমি একই কাঠামো (কোনও সূচক ছাড়াই) এবং অনুরূপ কার্ডিনালিটি সহ একটি টেস্ট টেবিল তৈরি করেছি। জাজানসের উত্তর প্রস্তাব করেছিল যে কারণটি আপডেটের জন্য ব্যবহৃত অস্থায়ী টেবিলের ক্রম হতে পারে। আমি সরাসরি হাইপোথিসিসটি পরীক্ষা করতে পারিনি কারণ আমার track_io_timing(অ্যামাজন আরডিএস ব্যবহার করে) অ্যাক্সেস নেই ।

  1. সামগ্রিক ফলাফলগুলি বেশ দ্রুত ছিল (বেশ কয়েকটিটির ফ্যাক্টর দ্বারা)। আমি অনুমান করছি যে এরভিনের উত্তরের সাথে সামঞ্জস্য রেখে সূচকগুলি অপসারণের কারণেই এটি ঘটেছে ।

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


1
কি হবে যদি আপনি সমতা শর্ত রূপান্তরিত (a = b)দুই "রয়েছে" শর্তাবলী: (a @> b AND b @> a)? পরিকল্পনা কি পরিবর্তন হয়?
ypercubeᵀᴹ

@ টাইপারকিউব: পরিকল্পনাটি এখনও বেশ অনুকূল নয়, যদিও আমার সম্পাদনা # 2 দেখুন।
অ্যাবিবোপরেবপ

1
আর একটি ধারণা হ'ল নিয়মিত বিটি্রি সূচক যুক্ত করা (lower(t_range),upper(t_range))যেহেতু আপনি সাম্যটি পরীক্ষা করেন।
ypercubeᵀᴹ

উত্তর:


9

আপনার কার্যকর করার পরিকল্পনাগুলির সময়ের সবচেয়ে বড় পার্থক্যটি শীর্ষ নোডে, নিজেই আপডেট UP এটি প্রস্তাব দেয় যে আপনার বেশিরভাগ সময় আপডেটের সময় আইওতে যায়। আপনি অনুসন্ধানগুলি চালু track_io_timingএবং এটি চালিয়ে যাচাই করতে পারেনEXPLAIN (ANALYZE, BUFFERS)

বিভিন্ন পরিকল্পনা বিভিন্ন ক্রমে আপডেট হওয়ার জন্য সারিগুলি উপস্থাপন করছে। একটি trip_idক্রমযুক্ত, এবং অপরটি যে কোনও ক্রমে তারা শারীরিকভাবে টেম্প সারণিতে উপস্থিত থাকতে পারে।

সারণি আপডেট করা হয়েছে বলে মনে হচ্ছে এটির দৈহিক শৃঙ্খলাটি ট্রিপ_আইডি কলামের সাথে সম্পর্কিত এবং এই ক্রমে সারিগুলি আপডেট করার ফলে পঠন-সামনের / অনুক্রমিক পঠনগুলির সাথে দক্ষ আইও প্যাটার্নগুলি নিয়ে যায়। যদিও টেম্প টেবিলের দৈহিক ক্রমটি মনে হয় প্রচুর এলোমেলোভাবে পড়ে।

আপনি যদি order by trip_idবিবৃতিতে কোনও টেম্প টেবিল তৈরি করতে পারেন তবে এটি আপনার সমস্যার সমাধান করতে পারে।

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

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


দুর্ভাগ্যক্রমে আমি সংশোধন করতে অক্ষম track_io_timing, এবং (যেহেতু এটি দেড় বছর হয়ে গেছে!) আমার আর মূল ডেটাতে অ্যাক্সেস নেই। তবে, আমি একই তত্ত্ব এবং একই আকারের (লক্ষ লক্ষ সারি) দিয়ে টেবিল তৈরি করে এবং দুটি পৃথক আপডেট চালিয়ে আপনার তত্ত্বটি পরীক্ষা করেছি - যার মধ্যে টেম্প আপডেটের টেবিলটি মূল টেবিলের মতো বাছাই করা হয়েছিল এবং অন্যটিতে এটি সাজানো হয়েছিল another আপাতদৃষ্টিতে এলোমেলোভাবে। দুর্ভাগ্যক্রমে, দুটি আপডেট প্রায় একই পরিমাণ সময় নেয়, তা বোঝায় যে আপডেট টেবিলের ক্রমটি এই কোয়েরিকে প্রভাবিত করে না।
abeboparebop

7

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

যেহেতু আপনার UPDATEসমস্ত বিদ্যমান 3 এম সারিগুলির এক তৃতীয়াংশ (!) পরিবর্তন করে, তাই একটি সূচক মোটেই সহায়তা করবে না । বিপরীতে, টেবিলের পাশাপাশি সূচকগুলি ক্রমবর্ধমান আপডেট করা আপনার জন্য যথেষ্ট পরিমাণে যুক্ত হতে চলেছে UPDATE

শুধু আপনার সাধারণ প্রশ্ন 1 রাখুন । সহজ, ভিত্তিগত সমাধান হয় সূচক ড্রপ সামনে UPDATE। অন্যান্য প্রয়োজনে আপনার যদি এটির প্রয়োজন হয় তবে এটি পরে তৈরি করুন UPDATE। বৃহত্তর সময় সূচকটি বজায় রাখার চেয়ে এটি আরও দ্রুত হবে UPDATE

একটি জন্য UPDATEসব সারি এক তৃতীয়াংশ উপর, এটা সম্ভবত পাশাপাশি সব অন্যান্য ইনডেক্স ড্রপ দিতে হবে - এবং তাদের পরে পুনরায় তৈরি UPDATE। একমাত্র ক্ষতি: আপনার অতিরিক্ত সুবিধাগুলি এবং টেবিলে একটি এক্সক্লুসিভ লক প্রয়োজন (কেবলমাত্র যদি আপনি ব্যবহার করেন তবে সংক্ষিপ্ত মুহুর্তের জন্য CREATE INDEX CONCURRENTLY)।

জিআইএসটি সূচকের পরিবর্তে বিয়ারি ব্যবহারের জন্য ইয়ারকিউবের ধারণা মূলত ভাল বলে মনে হচ্ছে। কিন্তু না সব সারি এক তৃতীয়াংশ (যেখানে কোন সূচক কোন ভাল দিয়ে শুরু করতে), এবং জন্য না শুধু (lower(t_range),upper(t_range)), যেহেতু tstzrangeনা একটি বিযুক্ত পরিসীমা প্রকার।

বেশিরভাগ বিচ্ছিন্ন পরিসরের ধরণের একটি প্রচলিত রূপ রয়েছে যা "সমতা" ধারণাটি সহজ করে তোলে: ক্যানোনিকাল আকারে মানের নিম্ন এবং উপরের সীমা এটি সংজ্ঞায়িত করে। ডকুমেন্টেশন:

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

বিল্ট-ইন পরিসীমা ধরনের int4range, int8rangeএবং daterangeসব ব্যবহার ক্যানোনিকাল ফর্ম নিম্ন আবদ্ধ এবং বাদ উপরের আবদ্ধ অন্তর্ভুক্ত; যে [),। ব্যবহারকারী-সংজ্ঞায়িত পরিসীমা প্রকারগুলি তবে অন্যান্য কনভেনশন ব্যবহার করতে পারে।

এটি ক্ষেত্রে নয় tstzrange, যেখানে সমতা জন্য উচ্চ এবং নিম্ন সীমানার অন্তর্ভুক্তি বিবেচনা করা প্রয়োজন। একটি সম্ভাব্য বিটি্রি সূচি চালু থাকতে হবে:

(lower(t_range), upper(t_range), lower_inc(t_range), upper_inc(t_range))

এবং WHEREকোয়েরিতে ক্লোজে একই অভিব্যক্তিটি ব্যবহার করতে হবে ।

একমাত্র পুরো মানটিকে indexালাইয়ের জন্য প্রলুব্ধ করা যেতে পারে text: (cast(t_range AS text))- তবে এই প্রকাশটি IMMUTABLEযেহেতু timestamptzমানগুলির পাঠ্য উপস্থাপনা বর্তমান timezoneসেটিংসের উপর নির্ভর করে । আপনার একটি IMMUTABLEমোড়ক ফাংশনে অতিরিক্ত পদক্ষেপ স্থাপন করা দরকার যা একটি প্রচলিত ফর্ম তৈরি করে এবং এতে একটি কার্যকরী সূচক তৈরি করতে পারে ...

অতিরিক্ত ব্যবস্থা / বিকল্প ধারণা

যদি shape_dist_traveledইতিমধ্যে tt.shape_dist_traveledআপনার কয়েকটি আপডেট হওয়া সারিগুলিরও বেশি এর সমান মান থাকতে পারে (এবং আপনি আপনার UPDATEপছন্দসই ট্রিগারগুলির কোনও পার্শ্ব প্রতিক্রিয়ার উপর নির্ভর করেন না ...), খালি আপডেটগুলি বাদ দিয়ে আপনি আপনার ক্যোয়ারীটিকে আরও দ্রুত তৈরি করতে পারেন:

WHERE ...
AND   shape_dist_traveled IS DISTINCT FROM tt.shape_dist_traveled;

অবশ্যই, পারফরম্যান্স অপটিমাইজেশনের জন্য সমস্ত সাধারণ পরামর্শ প্রযোজ্য। পোস্টগ্রিস উইকি একটি ভাল সূচনা পয়েন্ট।

VACUUM FULLআপনার জন্য বিষ হতে পারে, যেহেতু কিছু মৃত টিপলস (বা স্থান সংরক্ষিত FILLFACTOR) UPDATEপারফরম্যান্সের জন্য উপকারী ।

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

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