পোস্টগ্রিএসকিউএল কেন আরও ব্যয়বহুল যোগদানের আদেশটি বেছে নিচ্ছে?


13

পোস্টগ্রিএসকিউএল ডিফল্ট, প্লাস ব্যবহার করে

default_statistics_target=1000
random_page_cost=1.5

সংস্করণ

PostgreSQL 10.4 on x86_64-pc-linux-musl, compiled by gcc (Alpine 6.4.0) 6.4.0, 64-bit

আমি শূন্য এবং বিশ্লেষণ করেছি। প্রশ্নটি খুব সোজা:

SELECT r.price
FROM account_payer ap
  JOIN account_contract ac ON ap.id = ac.account_payer_id
  JOIN account_schedule "as" ON ac.id = "as".account_contract_id
  JOIN schedule s ON "as".id = s.account_schedule_id
  JOIN rate r ON s.id = r.schedule_id
WHERE ap.account_id = 8

প্রতিটি idকলামটি মূল কী এবং এতে যোগদান করা সমস্ত কিছুই বিদেশী কী সম্পর্ক এবং প্রতিটি বিদেশী কীতে একটি সূচক থাকে। প্লাস জন্য একটি সূচক account_payer.account_id

76k সারি ফিরিয়ে আনতে এটি 3.93s লাগে।

Merge Join  (cost=8.06..83114.08 rows=3458267 width=6) (actual time=0.228..3920.472 rows=75548 loops=1)
  Merge Cond: (s.account_schedule_id = "as".id)
  ->  Nested Loop  (cost=0.57..280520.54 rows=6602146 width=14) (actual time=0.163..3756.082 rows=448173 loops=1)
        ->  Index Scan using schedule_account_schedule_id_idx on schedule s  (cost=0.14..10.67 rows=441 width=16) (actual time=0.035..0.211 rows=89 loops=1)
        ->  Index Scan using rate_schedule_id_code_modifier_facility_idx on rate r  (cost=0.43..486.03 rows=15005 width=10) (actual time=0.025..39.903 rows=5036 loops=89)
              Index Cond: (schedule_id = s.id)
  ->  Materialize  (cost=0.43..49.46 rows=55 width=8) (actual time=0.060..12.984 rows=74697 loops=1)
        ->  Nested Loop  (cost=0.43..49.32 rows=55 width=8) (actual time=0.048..1.110 rows=66 loops=1)
              ->  Nested Loop  (cost=0.29..27.46 rows=105 width=16) (actual time=0.030..0.616 rows=105 loops=1)
                    ->  Index Scan using account_schedule_pkey on account_schedule "as"  (cost=0.14..6.22 rows=105 width=16) (actual time=0.014..0.098 rows=105 loops=1)
                    ->  Index Scan using account_contract_pkey on account_contract ac  (cost=0.14..0.20 rows=1 width=16) (actual time=0.003..0.003 rows=1 loops=105)
                          Index Cond: (id = "as".account_contract_id)
              ->  Index Scan using account_payer_pkey on account_payer ap  (cost=0.14..0.21 rows=1 width=8) (actual time=0.003..0.003 rows=1 loops=105)
                    Index Cond: (id = ac.account_payer_id)
                    Filter: (account_id = 8)
                    Rows Removed by Filter: 0
Planning time: 5.843 ms
Execution time: 3929.317 ms

যদি আমি সেট করি তবে join_collapse_limit=1এটি 0.1x সেকেন্ডে 25x স্পিডআপ লাগে।

Nested Loop  (cost=6.32..147323.97 rows=3458267 width=6) (actual time=8.908..151.860 rows=75548 loops=1)
  ->  Nested Loop  (cost=5.89..390.23 rows=231 width=8) (actual time=8.730..11.655 rows=66 loops=1)
        Join Filter: ("as".id = s.account_schedule_id)
        Rows Removed by Join Filter: 29040
        ->  Index Scan using schedule_pkey on schedule s  (cost=0.27..17.65 rows=441 width=16) (actual time=0.014..0.314 rows=441 loops=1)
        ->  Materialize  (cost=5.62..8.88 rows=55 width=8) (actual time=0.001..0.011 rows=66 loops=441)
              ->  Hash Join  (cost=5.62..8.61 rows=55 width=8) (actual time=0.240..0.309 rows=66 loops=1)
                    Hash Cond: ("as".account_contract_id = ac.id)
                    ->  Seq Scan on account_schedule "as"  (cost=0.00..2.05 rows=105 width=16) (actual time=0.010..0.028 rows=105 loops=1)
                    ->  Hash  (cost=5.02..5.02 rows=48 width=8) (actual time=0.178..0.178 rows=61 loops=1)
                          Buckets: 1024  Batches: 1  Memory Usage: 11kB
                          ->  Hash Join  (cost=1.98..5.02 rows=48 width=8) (actual time=0.082..0.143 rows=61 loops=1)
                                Hash Cond: (ac.account_payer_id = ap.id)
                                ->  Seq Scan on account_contract ac  (cost=0.00..1.91 rows=91 width=16) (actual time=0.007..0.023 rows=91 loops=1)
                                ->  Hash  (cost=1.64..1.64 rows=27 width=8) (actual time=0.048..0.048 rows=27 loops=1)
                                      Buckets: 1024  Batches: 1  Memory Usage: 10kB
                                      ->  Seq Scan on account_payer ap  (cost=0.00..1.64 rows=27 width=8) (actual time=0.009..0.023 rows=27 loops=1)
                                            Filter: (account_id = 8)
                                            Rows Removed by Filter: 24
  ->  Index Scan using rate_schedule_id_code_modifier_facility_idx on rate r  (cost=0.43..486.03 rows=15005 width=10) (actual time=0.018..1.685 rows=1145 loops=66)
        Index Cond: (schedule_id = s.id)
Planning time: 4.692 ms
Execution time: 160.585 ms

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

মন্তব্যের মাধ্যমে অতিরিক্ত তথ্য অনুরোধ করা হয়েছে

কি rate_schedule_id_code_modifier_facility_idxএকটি যৌগ সূচক?

এটি schedule_idপ্রথম কলাম হওয়ার সাথে সাথে । আমি এটিকে উত্সর্গীকৃত সূচক তৈরি করেছি এবং এটি ক্যোয়ারী পরিকল্পনাকারী বেছে নিয়েছে তবে এটি কার্য সম্পাদনকে প্রভাবিত করে না বা পরিকল্পনাকে অন্যথায় প্রভাবিত করে না।


আপনি কি সেটিংস পরিবর্তন করতে পারেন default_statistics_targetএবং random_page_costতাদের ডিফল্টে ফিরে যেতে পারেন? আপনি default_statistics_targetএখনও আরও উত্থাপন যখন কি হবে ? আপনি কি একটি ডিবি ফিডল (dbfiddle.uk এ) তৈরি করতে পারেন এবং সেখানে সমস্যাটি পুনরুত্পাদন করার চেষ্টা করতে পারেন?
কলিন টি হার্ট

3
আপনার ডেটা সম্পর্কে স্কাই / অদ্ভুত কিছু আছে কিনা তা দেখার জন্য আপনি প্রকৃত পরিসংখ্যানটি পরীক্ষা করতে পারেন? postgresql.org/docs/10/static/planner-stats.html
কলিন 'হার্ট

প্যারামিটারের জন্য বর্তমান মান কী work_mem? এটি পরিবর্তন করা বিভিন্ন সময় দেয়?
eppesuig

উত্তর:


1

মনে হয় আপনার পরিসংখ্যান নির্ভুল নয় (এগুলি রিফ্রেশ করার জন্য ভ্যাকুয়াম বিশ্লেষণ করুন) হয় আপনি আপনার মডেলটিতে কলামগুলি সংযুক্ত করেছেন (এবং সুতরাং আপনাকে create statisticsসেই সত্যটির পরিকল্পনাকারীকে অবহিত করার জন্য সঞ্চালন করতে হবে )।

join_collapseপরামিতি পুনরায় সাজাতে পরিকল্পক যোগদান করে তাই এটি প্রথম এক যে কম ডেটা নিয়ে আসে সঞ্চালিত পারেন। তবে, পারফরম্যান্সের জন্য, আমরা পরিকল্পনাকারীকে অনেকগুলি যোগদানের সাথে কোয়েরিতে এটি করতে দিতে পারি না। ডিফল্টরূপে, এটি 8 টিতে সর্বাধিক যোগদান করে। এটি 1 এ সেট করে আপনি কেবল সেই ক্ষমতাটি অক্ষম করে দিন।

তাহলে পোস্টগ্রিজ কীভাবে এই ক্যোয়ারীটি পেতে কতগুলি সারি আনা উচিত? এটি সারিগুলির সংখ্যা অনুমান করতে পরিসংখ্যান ব্যবহার করে।

আপনার ব্যাখ্যার পরিকল্পনাগুলিতে আমরা যা দেখতে পাচ্ছি তা হ'ল এখানে বেশ কয়েকটি অসম্পূর্ণ সারি সংখ্যা অনুমান (প্রথম মানটি অনুমান, দ্বিতীয়টি আসল)।

উদাহরণস্বরূপ, এখানে:

Materialize  (cost=0.43..49.46 rows=55 width=8) (actual time=0.060..12.984 rows=74697 loops=1)

পরিকল্পনাকারী যখন তিনি আসলে 69৪69 actually actually পেয়েছেন তখন 55 টি সারি পাওয়ার অনুমান।

আমি কি করব (যদি আমি আপনার জুতোতে থাকতাম):

  • analyze পরিসংখ্যান রিফ্রেশ জড়িত পাঁচটি টেবিল
  • আবার দেখাও explain analyze
  • অনুমান সারি সংখ্যা এবং প্রকৃত সারি সংখ্যাগুলির মধ্যে পার্থক্যটি দেখুন
  • যদি অনুমানের সারির নম্বরগুলি সঠিক হয়, তবে পরিকল্পনাটি পরিবর্তিত হয়েছে এবং আরও কার্যকর। যদি সবকিছু ঠিক থাকে তবে আপনি নিজের অটোভ্যাকুম সেটিংস পরিবর্তন করতে পারেন তাই বিশ্লেষণ করুন (এবং ভ্যাকুয়াম) আরও প্রায়শই সম্পাদন করে
  • অনুমান সারি সংখ্যা এখনও ভুল, এটা দেখে মনে হচ্ছে আপনি আপনার সারণীতে ডেটা সম্পর্কিত আছে (তৃতীয় স্বাভাবিক ফর্ম লঙ্ঘন) .আপনি সঙ্গে এটি প্রকাশক বিবেচনা করতে পারেন CREATE STATISTICS(ডকুমেন্টেশন এখানে )

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

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