GROUP BY এবং অর্ডার দিয়ে বড় টেবিলের কাছে ধীরে ধীরে ক্যোরিয়াস


14

আমার কাছে 7.2 মিলিয়ন টিপলসযুক্ত একটি টেবিল রয়েছে যা দেখতে এটির মতো দেখাচ্ছে:

                               table public.methods
 column |          type         |                      attributes
--------+-----------------------+----------------------------------------------------
 id     | integer               | not null DEFAULT nextval('methodkey'::regclass)
 hash   | character varying(32) | not null
 string | character varying     | not null
 method | character varying     | not null
 file   | character varying     | not null
 type   | character varying     | not null
Indexes:
    "methods_pkey" PRIMARY KEY, btree (id)
    "methodhash" btree (hash)

এখন আমি কয়েকটি মান নির্বাচন করতে চাই তবে ক্যোয়ারীটি অবিশ্বাস্যরূপে ধীর:

db=# explain 
    select hash, string, count(method) 
    from methods 
    where hash not in 
          (select hash from nostring) 
    group by hash, string 
    order by count(method) desc;
                                            QUERY PLAN
----------------------------------------------------------------------------------------
 Sort  (cost=160245190041.10..160245190962.07 rows=368391 width=182)
   Sort Key: (count(methods.method))
   ->  GroupAggregate  (cost=160245017241.77..160245057764.73 rows=368391 width=182)
       ->  Sort  (cost=160245017241.77..160245026451.53 rows=3683905 width=182)
             Sort Key: methods.hash, methods.string
             ->  Seq Scan on methods  (cost=0.00..160243305942.27 rows=3683905 width=182)
                   Filter: (NOT (SubPlan 1))
                   SubPlan 1
                   ->  Materialize  (cost=0.00..41071.54 rows=970636 width=33)
                     ->  Seq Scan on nostring  (cost=0.00..28634.36 rows=970636 width=33)

hashকলামের MD5 হ্যাশ হয় stringএবং একটি সূচক হয়েছে। সুতরাং আমি আমার সমস্যাটি মনে করি যে পুরো টেবিলটি আইডি দ্বারা বাছাই করা হয় হ্যাশ দ্বারা নয়, তাই এটি প্রথমে বাছাই করতে কিছুক্ষণ সময় নেয় এবং তারপরে এটি গোষ্ঠীভূত করে?

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

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


1
আপনি সর্বদা পোস্টগ্রিজ এসকিউএল এর সংস্করণ সরবরাহ করুনNULLকলামে মানগুলির শতাংশ কত method? অনুলিপি আছে string?
এরউইন ব্র্যান্ডসটেটার

উত্তর:


18

LEFT JOINমধ্যে @ dezso এর উত্তর ভাল হওয়া উচিত। তবে একটি সূচী খুব কমই কার্যকর হবে (প্রতি সে), কারণ কোয়েরিতে যে কোনওভাবেই পুরো টেবিলটি পড়তে হবে - ব্যতিক্রমটি কেবল পোস্টগ্রিস 9.2+ এবং অনুকূল অবস্থার মধ্যে কেবল সূচক-স্ক্যান হওয়া, নীচে দেখুন।

SELECT m.hash, m.string, count(m.method) AS method_ct
FROM   methods m
LEFT   JOIN nostring n USING (hash)
WHERE  n.hash IS NULL
GROUP  BY m.hash, m.string 
ORDER  BY count(m.method) DESC;

EXPLAIN ANALYZEক্যোয়ারিতে চালান । নগদ প্রভাব এবং শব্দ বাদ দিতে বেশ কয়েকবার। সেরা ফলাফলের সাথে তুলনা করুন।

আপনার প্রশ্নের সাথে মেলে এমন একটি বহু-কলাম সূচক তৈরি করুন:

CREATE INDEX methods_cluster_idx ON methods (hash, string, method);

কেন অপেক্ষা করবেন? আমি বলার পরে একটি সূচক সাহায্য করবে না? ভাল, আমাদের এটি CLUSTERটেবিলে দরকার:

CLUSTER methods USING methods_cluster_idx;
ANALYZE methods;

পুনরায় EXPLAIN ANALYZE। কোন দ্রুত? এটা করা উচিত.

CLUSTERব্যবহৃত সূচির ক্রমে পুরো টেবিলটি পুনরায় লেখার জন্য এককালীন ক্রিয়াকলাপ। এটি কার্যকরভাবে একটি VACUUM FULL। আপনি যদি নিশ্চিত হতে চান তবে এর সাথে VACUUM FULLকী দায়ী হতে পারে তা দেখতে আপনি একা একটি প্রাক পরীক্ষা চালিয়ে যাবেন ।

যদি আপনার টেবিলটি প্রচুর রচনামূলক ক্রিয়াকলাপ দেখে তবে প্রভাব সময়ের সাথে সাথে হ্রাস পাবে। CLUSTERপ্রভাবটি পুনরুদ্ধার করতে অফ-ঘন্টা এ শিডিউল করুন । ফাইন টিউনিং আপনার সঠিক ব্যবহারের ক্ষেত্রে নির্ভর করে। ম্যানুয়াল সম্পর্কে CLUSTER

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


যদিNULL কলামে মানগুলির শতাংশের পরিমাণ বেশি methodহয় (প্রকৃত সারি আকারের উপর নির্ভর করে 20% ডলারের বেশি), একটি আংশিক সূচীতে সহায়তা করা উচিত:

CREATE INDEX methods_foo_idx ON methods (hash, string)
WHERE method IS NOT NULL;

(আপনার পরবর্তী আপডেটগুলি আপনার কলামগুলি হ'ল NOT NULLতাই প্রযোজ্য নয় shows )

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

উল্লিখিত আংশিক সূচকটি সে ক্ষেত্রে আরও কার্যকর হতে পারে।

তাহলে , অপরপক্ষে, আছে কোন NULL কলামে মান method, আপনি উচিত
1.) সংজ্ঞায়িত এটা NOT NULLএবং
2.) ব্যবহারের count(*)পরিবর্তে count(method)সামান্য দ্রুত গতিতে চলে এবং অভাবে একই আছে যে NULLমান।

আপনার যদি এই কোয়েরিটি প্রায়শই কল করতে হয় এবং সারণীটি কেবল পঠনযোগ্য হয় তবে একটি তৈরি করুন MATERIALIZED VIEW


বহিরাগত সূক্ষ্ম বিন্দু: আপনার টেবিলটির নাম দেওয়া হয়েছে nostring, তবুও মনে হচ্ছে হ্যাশ রয়েছে। স্ট্রিংয়ের পরিবর্তে হ্যাশগুলি বাদ দিয়ে এমন একটি সম্ভাবনা রয়েছে যা আপনি ইচ্ছা করেই বেশি স্ট্রিং বাদ দেন। অত্যন্ত অসম্ভব, তবে সম্ভব।


ক্লাস্টারের সাথে এটি আরও দ্রুত। এখনও ক্যোয়ারির জন্য
মিনিটের চারপাশে

@ রিওক্স: যেহেতু আপনি v9.2 চালাচ্ছেন: আপনি কি ক্লাস্টারিংয়ের আগে কেবল সূচক দিয়ে পরীক্ষা করেছিলেন? আপনি একটি পার্থক্য দেখলে আকর্ষণীয় হবে। (ক্লাস্টারিংয়ের পরে আপনি পার্থক্যটি পুনরুত্পাদন করতে পারবেন না)) এছাড়াও (এবং এটি সস্তা হবে), কী এখন কোনও সূচক স্ক্যান বা একটি পূর্ণ টেবিল স্ক্যান প্রদর্শন করে?
এরউইন ব্র্যান্ডস্টেটর

5

ডিবিএ.এসই তে স্বাগতম!

আপনি আপনার ক্যোয়ারীটিকে এভাবে পুনরায় প্রকাশ করার চেষ্টা করতে পারেন:

SELECT m.hash, string, count(method) 
FROM 
    methods m
    LEFT JOIN nostring n ON m.hash = n.hash
WHERE n.hash IS NULL
GROUP BY hash, string 
ORDER BY count(method) DESC;

বা অন্য সম্ভাবনা:

SELECT m.hash, string, count(method) 
FROM 
    methods m
WHERE NOT EXISTS (SELECT hash FROM nostring WHERE hash = m.hash)
GROUP BY hash, string 
ORDER BY count(method) DESC;

NOT IN পারফরম্যান্সের জন্য এটি একটি সাধারণ ডোবা কারণ এটির সাথে কোনও সূচক ব্যবহার করা শক্ত।

এটি সূচকগুলির সাথে আরও বাড়ানো যেতে পারে। একটি সূচক nostring.hashদরকারী দেখায়। তবে প্রথম: এখন কী পাবে? (আউটপুটটি দেখার চেয়ে ভাল হবে EXPLAIN ANALYZEযেহেতু ব্যয়গুলি অপারেশনগুলির সময় বলে না tell


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

3
ব্যয়টি কেবল পরিকল্পনাকারীর পক্ষে যথেষ্ট পরিমাণে ভাল পরিকল্পনা তৈরি করতে সক্ষম হয়। আসল সময়গুলি সাধারণত এটির সাথে সম্পর্কিত হয়, তবে অগত্যা নয়। সুতরাং আপনি যদি নিশ্চিত হতে চান, ব্যবহার করুন EXPLAIN ANALYZE
dezso

1

হ্যাশ যেহেতু একটি এমডি 5, আপনি সম্ভবত এটি একটি সংখ্যায় রূপান্তর করার চেষ্টা করতে পারেন: আপনি এটি একটি সংখ্যা হিসাবে সঞ্চয় করতে পারেন, বা কেবল একটি কার্যকরী সূচি তৈরি করতে পারেন যা একটি সংখ্যাটিকে অপরিবর্তনীয় ফাংশনে গণনা করে।

অন্যান্য ব্যক্তি ইতিমধ্যে একটি pl / pgsql ফাংশন তৈরি করেছেন যা একটি এমডি 5 মানকে পাঠ্য থেকে স্ট্রিংয়ে রূপান্তর করে। উদাহরণের জন্য /programming/9809381/hashing-a-string-to-a-numeric-value-in-postgressql দেখুন

আমি বিশ্বাস করি যে সূচি স্ক্যান করার সময় আপনি সত্যই স্ট্রিং তুলনায় অনেক সময় ব্যয় করছেন। যদি আপনি এই মানটি একটি সংখ্যা হিসাবে সঞ্চয় করতে পরিচালনা করেন তবে তা সত্যিই দ্রুত হওয়া উচিত।


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

2
আমি মনে করি আমি এমডি 5 কে স্থানের দক্ষতার জন্য সংখ্যাটির চেয়ে বাইটি হিসাবে সঞ্চয় করেছিলাম: sqlfiddle.com/#!12/d41d8/252
জ্যাক বলেছেন শীর্ষস্থানীয়রা.অক্সিজ

এছাড়াও, dba.se স্বাগতম!
জ্যাক বলছেন topanswers.xyz

@ জ্যাকডুগলাস: আকর্ষণীয় মন্তব্য! বড় টেবিলের জন্য 32 এর পরিবর্তে 16 বাইট প্রতি এমডি 5 বেশ কিছুটা।
এরউইন ব্র্যান্ডসটেটার

0

আমি এই ইস্যুটিকে অনেকটা চালিয়েছি এবং একটি সাধারণ 2-অংশের কৌশল আবিষ্কার করেছি।

  1. হ্যাশ মানটিতে সাবস্ট্রিং সূচক তৈরি করুন: (7 সাধারণত একটি ভাল দৈর্ঘ্য হয়)

    create index methods_idx_hash_substring ON methods(substring(hash,1,7))

  2. আপনার অনুসন্ধানগুলি / যোগদানগুলিতে একটি স্ট্রিং ম্যাচ অন্তর্ভুক্ত করুন, সুতরাং ক্যোয়ারী পরিকল্পনাকারী সূচকটি ব্যবহার করার ইঙ্গিতযুক্ত:

    পুরানো: WHERE hash = :kwarg

    নতুন: WHERE (hash = :kwarg) AND (substring(hash,1,7) = substring(:kwarg,1,7))

আপনার কাঁচাতেও একটি সূচি থাকা উচিত hash

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

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