প্রাইমারি কীতে সূচক সহজ যোগে ব্যবহৃত হয় না


16

আমার নিম্নলিখিত সারণী এবং সূচী সংজ্ঞা রয়েছে:

CREATE TABLE munkalap (
    munkalap_id serial PRIMARY KEY,
    ...
);

CREATE TABLE munkalap_lepes (
    munkalap_lepes_id serial PRIMARY KEY,
    munkalap_id integer REFERENCES munkalap (munkalap_id),
    ...
);

CREATE INDEX idx_munkalap_lepes_munkalap_id ON munkalap_lepes (munkalap_id);

মুঙ্কালাপ_আইডি-তে সূচকের কোনওটি কেন নিম্নলিখিত কোয়েরিতে ব্যবহৃত হচ্ছে না?

EXPLAIN ANALYZE SELECT ml.* FROM munkalap m JOIN munkalap_lepes ml USING (munkalap_id);

QUERY PLAN
Hash Join  (cost=119.17..2050.88 rows=38046 width=214) (actual time=0.824..18.011 rows=38046 loops=1)
  Hash Cond: (ml.munkalap_id = m.munkalap_id)
  ->  Seq Scan on munkalap_lepes ml  (cost=0.00..1313.46 rows=38046 width=214) (actual time=0.005..4.574 rows=38046 loops=1)
  ->  Hash  (cost=78.52..78.52 rows=3252 width=4) (actual time=0.810..0.810 rows=3253 loops=1)
        Buckets: 1024  Batches: 1  Memory Usage: 115kB
        ->  Seq Scan on munkalap m  (cost=0.00..78.52 rows=3252 width=4) (actual time=0.003..0.398 rows=3253 loops=1)
Total runtime: 19.786 ms

আমি ফিল্টার যুক্ত করলেও এটি সমান:

EXPLAIN ANALYZE SELECT ml.* FROM munkalap m JOIN munkalap_lepes ml USING (munkalap_id) WHERE NOT lezarva;

QUERY PLAN
Hash Join  (cost=79.60..1545.79 rows=1006 width=214) (actual time=0.616..10.824 rows=964 loops=1)
  Hash Cond: (ml.munkalap_id = m.munkalap_id)
  ->  Seq Scan on munkalap_lepes ml  (cost=0.00..1313.46 rows=38046 width=214) (actual time=0.007..5.061 rows=38046 loops=1)
  ->  Hash  (cost=78.52..78.52 rows=86 width=4) (actual time=0.587..0.587 rows=87 loops=1)
        Buckets: 1024  Batches: 1  Memory Usage: 4kB
        ->  Seq Scan on munkalap m  (cost=0.00..78.52 rows=86 width=4) (actual time=0.014..0.560 rows=87 loops=1)
              Filter: (NOT lezarva)
Total runtime: 10.911 ms

উত্তর:


22

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

কোনও ক্যোয়ারির পরিকল্পনা করার সময়, পোস্টগ্রিসের পরিকল্পনাকারী বিভিন্ন সম্ভাব্য স্কিমের আওতায় বিভিন্ন ক্রিয়াকলাপের (গণনা, অনুক্রমিক এবং এলোমেলো আইও) ব্যয় নির্ধারণ করে এবং এটি সর্বনিম্ন ব্যয় হিসাবে অনুমান করে এমন পরিকল্পনা গ্রহণ করে। ঘোরানো স্টোরেজ (ডিস্ক) থেকে আইও করার সময়, র্যান্ডম আইও সাধারণত সিক্যুয়াল আইওর চেয়ে যথেষ্ট ধীর হয়, র্যান্ডম_পেজ_কোস্টের জন্য ডিফল্ট pg কনফিগারেশন এবং সেক_পৃষ্ঠা_কোস্টের ব্যয় হিসাবে 4: 1 পার্থক্য অনুমান করে।

এই যোগদানগুলি বা ফিল্টার পদ্ধতির কথা বিবেচনা করার সময় এই বিবেচনাগুলি কার্যকর হয় যা একটি সূচ বনাম একটিকে ক্রমবর্ধমানভাবে একটি টেবিল স্ক্যান করে। একটি সূচক ব্যবহার করার সময়, পরিকল্পনাটি সূচকের মাধ্যমে দ্রুত একটি সারি খুঁজে পেতে পারে, তারপরে সারিটির ডেটা সমাধান করার জন্য একটি এলোমেলো ব্লক পড়ার জন্য অ্যাকাউন্ট করতে হবে। আপনার দ্বিতীয় ক্যোয়ারির ক্ষেত্রে যা ফিল্টারিং প্রাকটিকেট যুক্ত করেছে WHERE NOT lezarva, আপনি দেখতে পাচ্ছেন যে কীভাবে পরিকল্পনার প্রাক্কলনকে বিশদ বিশ্লেষণের ফলাফলগুলিতে এটি প্রভাবিত করেছিল। পরিকল্পনাকারী যোগ দেওয়ার ফলে 1006 টি সারি অনুমান করে (যা 964 এর প্রকৃত ফলাফল সেটটির সাথে খুব ঘনিষ্ঠভাবে মেলে)। বৃহত্তর টেবিলটি মুঙ্কালাপ_লেপগুলিতে প্রায় 38 কে সারি রয়েছে, পরিকল্পনাকারী দেখেন যে যোগদানটিতে টেবিলের প্রায় 1006/38046 বা 1/38 সারিগুলি অ্যাক্সেস করতে হবে। এটি এও জানে যে গড় সারির প্রস্থটি 214 বাইট এবং একটি ব্লক 8 কে, সুতরাং প্রায় 38 টি সারি / ব্লক রয়েছে।

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

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


ধন্যবাদ, এটি এ পর্যন্ত আমার পড়া সবচেয়ে ভাল (এবং সবচেয়ে সংক্ষিপ্ত) বিবরণ। কয়েকটি মূল বিষয় পরিষ্কার করেছেন।
dezso

1
দুর্দান্ত ব্যাখ্যা। সারি / ডেটা পৃষ্ঠার গণনা কিছুটা বন্ধ। আপনাকে প্রতি সারি আইটেম পয়েন্টারটির জন্য পৃষ্ঠা শিরোনাম (24 বাইট) + 4 বাইট + ফাংশন করতে হবে + সারি শিরোনাম HeapTupleHeader( সারি প্রতি 23 বাইট) + ম্যাকালিজিন অনুসারে ন্যূনাল বিটমাস্ক + সারিবদ্ধকরণ। পরিশেষে, কলামগুলির ডেটা ধরণের এবং তাদের ক্রমের উপর নির্ভর করে ডেটা সাজানোর কারণে অজানা পরিমাণ প্যাডিং। সব মিলিয়ে এই ক্ষেত্রে 8 কেবি পৃষ্ঠায় 33 টিরও বেশি সারি নেই। (টোস্টকে অ্যাকাউন্টে নিচ্ছেন না))
এরউইন ব্র্যান্ডসেটেটার

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

1
@ ডিবেনহুর: আপনি EXPLAIN ANALYZE SELECT foo from barযাচাই করতে একটি বেসিক ডামি টেবিল দিয়ে দ্রুত চালাতে পারেন । এছাড়াও, প্রকৃত অন-ডিস্ক স্পেস ডেটা প্রান্তিককরণের উপর নির্ভর করে, যখন কেবলমাত্র কয়েকটি সারি পুনরুদ্ধার করা হয় তখন এটি কার্যকর করা কঠিন। সারি প্রস্থ EXPLAINকলামগুলির পুনরুদ্ধার করা সেটের জন্য প্রাথমিক স্থানের প্রয়োজনীয়তার প্রতিনিধিত্ব করে।
এরউইন ব্র্যান্ডসটেটার

5

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


হ্যাঁ, আপনি ঠিক বলেছেন :) আমি আরও একটি সুনির্দিষ্ট ক্ষেত্রে পরিস্থিতি স্পষ্ট করার চেষ্টা করেছি, শেষ প্রশ্নটি দেখুন।
dezso

@ ডেজো: একই জিনিস। যদি আপনার কোনও সূচক থাকে (lezarva, munkalap_id)এবং এটি যথেষ্ট পরিমাণে নির্বাচনী হয়, তবে এটি ব্যবহৃত হতে পারে। NOTকম সম্ভাব্য তোলে।
ypercubeᵀᴹ

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

1
@ ডিজেসো সারিগুলির দৈর্ঘ্য 214 বাইট প্রশস্ত, সুতরাং আপনার 8 কে ডেটা ব্লকে প্রতি 40 সারি থেকে কিছুটা কম থাকবে। সূচকের নির্বাচকতা প্রায় 1/40 (1006/38046)। সুতরাং, পিজি পরিসংখ্যান অনুসারে যে সমস্ত ব্লকগুলি ক্রমিকভাবে পড়া সস্তার হয় তবে সূচকটি ব্যবহার করার সময় এলোমেলোভাবে একই সংখ্যক ব্লকের সম্ভাব্য পঠন। এই আনুমানিক ট্রেডসগুলি কার্যকর_ক্যাস_সাইজ এবং র্যান্ডম_পেজ_কাস্ট কনফিগারেশন মান দ্বারা প্রভাবিত হতে পারে।
dbenhur

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