postgresql COUNT (DISTINCT…) খুব ধীর


166

আমার একটি খুব সাধারণ এসকিউএল কোয়েরি রয়েছে:

SELECT COUNT(DISTINCT x) FROM table;

আমার টেবিলটিতে প্রায় 1.5 মিলিয়ন সারি রয়েছে। এই ক্যোয়ারী বেশ ধীরে ধীরে চলছে; তুলনায় এটি প্রায় 7.5s লাগে

 SELECT COUNT(x) FROM table;

যা প্রায় 435ms লাগে। পারফরম্যান্স উন্নত করতে আমার জিজ্ঞাসা পরিবর্তন করার কোন উপায় আছে? আমি গোষ্ঠীকরণ এবং একটি নিয়মিত গণনা করার চেষ্টা করেছি, পাশাপাশি x এর উপর একটি সূচক রেখেছি; উভয়েরই একই কার্যকর 7.5s সময় রয়েছে।


আমি তাই মনে করি না. 1.5 মিলিয়ন সারিগুলির স্বতন্ত্র মান পাওয়া সবেমাত্র ধীর হতে চলেছে।
রাই-

5
আমি কেবল এটি সি # তে চেষ্টা করেছি, স্মৃতি থেকে 1.5 মিলিয়ন পূর্ণসংখ্যার স্বতন্ত্র মানগুলি পাওয়া আমার কম্পিউটারে এক সেকেন্ডের বেশি সময় নেয়। সুতরাং আমি মনে করি আপনি সম্ভবত ভাগ্যের বাইরে আছেন।
রাই-

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

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

1
দয়া করে সমস্ত সূচকের সাথে সারণী সংজ্ঞা অন্তর্ভুক্ত করুন ( \dআউটপুট psqlভাল হয়) এবং আপনার যে কলামটিতে সমস্যা রয়েছে তা সুনির্দিষ্টভাবে করুন। EXPLAIN ANALYZEউভয় প্রশ্নের দেখা ভাল হবে ।
ভাইগোরভ

উত্তর:


316

আপনি এটি ব্যবহার করতে পারেন:

SELECT COUNT(*) FROM (SELECT DISTINCT column_name FROM table_name) AS temp;

এটি এর চেয়ে অনেক দ্রুত:

COUNT(DISTINCT column_name)

38
পবিত্র জিজ্ঞাসা ব্যাটম্যান! এটি আমার পোস্টগ্রেসগুলি 190 এর দশকের থেকে 4.5 টি আলাদা গণনা করে!
রজারডপ্যাক

20
আমি এই থ্রেডটি www.postgresql.org এ পেয়েছি যা একই বিষয়: লিঙ্কটি নিয়ে আলোচনা করে । উত্তরগুলির মধ্যে একটি (জেফ জেনেস) বলেছেন যে COUNT (DISTINCT ()) হ্যাশ ব্যবহার না করে এর কাজটি করার জন্য টেবিলটি সাজায়।
অঙ্কুর

5
@ অঙ্কুর আমি আপনাকে প্রশ্ন জিজ্ঞাসা করতে পারি? যেহেতু COUNT(DISTINCT())বাছাই সম্পাদন করে, column_nameবিশেষত তুলনামূলকভাবে অল্প পরিমাণে work_mem(যেখানে হ্যাশিং তুলনামূলকভাবে প্রচুর পরিমাণে ব্যাচ উত্পাদন করবে) সাথে একটি সূচী তৈরি করা অবশ্যই সহায়ক হবে। যেহেতু, COUNT (DISTINCT () _) ব্যবহার করা সবসময় খারাপ না?
সেন্ট অ্যান্টারিও

2
@ মুসাহ্মান Count(column)কেবল নাল মানকে গণনা করে। count(*)সারি গণনা করে। সুতরাং প্রথম / দীর্ঘতর একটিটি নাল সারিটিও গণনা করবে (একবার)। count(column_name)তাদের সাথে একই আচরণ করার জন্য পরিবর্তন করুন।
GolezTrol

1
@ঙ্কুর এটি আমার পক্ষে খুব বেশি কার্যকর ছিল না .. কোনও উল্লেখযোগ্য উন্নতি পেলেন না।
শিওয়ানগিনি

11
-- My default settings (this is basically a single-session machine, so work_mem is pretty high)
SET effective_cache_size='2048MB';
SET work_mem='16MB';

\echo original
EXPLAIN ANALYZE
SELECT
        COUNT (distinct val) as aantal
FROM one
        ;

\echo group by+count(*)
EXPLAIN ANALYZE
SELECT
        distinct val
       -- , COUNT(*)
FROM one
GROUP BY val;

\echo with CTE
EXPLAIN ANALYZE
WITH agg AS (
    SELECT distinct val
    FROM one
    GROUP BY val
    )
SELECT COUNT (*) as aantal
FROM agg
        ;

ফলাফল:

original                                                      QUERY PLAN                                                      
----------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=36448.06..36448.07 rows=1 width=4) (actual time=1766.472..1766.472 rows=1 loops=1)
   ->  Seq Scan on one  (cost=0.00..32698.45 rows=1499845 width=4) (actual time=31.371..185.914 rows=1499845 loops=1)
 Total runtime: 1766.642 ms
(3 rows)

group by+count(*)
                                                         QUERY PLAN                                                         
----------------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=36464.31..36477.31 rows=1300 width=4) (actual time=412.470..412.598 rows=1300 loops=1)
   ->  HashAggregate  (cost=36448.06..36461.06 rows=1300 width=4) (actual time=412.066..412.203 rows=1300 loops=1)
         ->  Seq Scan on one  (cost=0.00..32698.45 rows=1499845 width=4) (actual time=26.134..166.846 rows=1499845 loops=1)
 Total runtime: 412.686 ms
(4 rows)

with CTE
                                                             QUERY PLAN                                                             
------------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=36506.56..36506.57 rows=1 width=0) (actual time=408.239..408.239 rows=1 loops=1)
   CTE agg
     ->  HashAggregate  (cost=36464.31..36477.31 rows=1300 width=4) (actual time=407.704..407.847 rows=1300 loops=1)
           ->  HashAggregate  (cost=36448.06..36461.06 rows=1300 width=4) (actual time=407.320..407.467 rows=1300 loops=1)
                 ->  Seq Scan on one  (cost=0.00..32698.45 rows=1499845 width=4) (actual time=24.321..165.256 rows=1499845 loops=1)
       ->  CTE Scan on agg  (cost=0.00..26.00 rows=1300 width=0) (actual time=407.707..408.154 rows=1300 loops=1)
     Total runtime: 408.300 ms
    (7 rows)

সিটিই হিসাবে একই পরিকল্পনা সম্ভবত অন্যান্য পদ্ধতি (উইন্ডো ফাংশন) দ্বারা উত্পাদিত হতে পারে


2
আপনি ক্যাশিং এর প্রভাব বিবেচনা করেছেন? পরবর্তীতে তিনটি "বিশ্লেষণ বিশ্লেষণ" করা হলে, প্রথমটি ডিস্ক থেকে জিনিসগুলি ধীরে ধীরে আনতে হতে পারে এবং দুটি পরেরটি মেমরি থেকে দ্রুত আনতে পারে।
tobixen

প্রকৃতপক্ষে: কার্যকর_ক্যাচি_সাইজ হ'ল টুইট করার প্রথম সেটিংস। খনিটি 2 জিবি, আইআইআরসি।
ওয়াইল্ডপ্লাজার

পারফরম্যান্সে কোনও পরিবর্তন ছাড়াই আমি আমার কার্যকর_ক্যাচি_ সাইজ 2 জিবিতে সেট করেছি। আপনি টুইটগুলি প্রস্তাব দেওয়ার মতো অন্য কোনও সেটিংস? যদি তা হয় তবে কী?
ferson2020

1) আপনি এটি সেট কিভাবে ? (আপনি কি এটি চূড়ান্ত করেছেন?) 2) আসলেই কি আপনার এত বেশি স্মৃতি পাওয়া যায়? 3) আপনার পরিকল্পনা আমাদের দেখান। ৪) হতে পারে আমার মেশিনটি দ্রুত, বা আপনার মোকাবেলায় আরও একযোগে বোঝা রয়েছে। @ ফার্সন2020: ঠিক আছে
ওয়াইল্ডপ্লাজার

আমি এটিকে স্টেটমেন্ট দিয়ে সেট করেছি: SET प्रभावी_cache_size = '2GB'; আমি অনেক স্মৃতি উপলব্ধ আছে। আমি আমার ক্যোয়ারী পরিকল্পনাটি অন্তর্ভুক্ত করার চেষ্টা করেছি, তবে এটি মন্তব্য বাক্সে খাপ খায় না।
ferson2020

2

যদি আপনার count(distinct(x))তুলনায় উল্লেখযোগ্যভাবে ধীর হয় count(x)তবে আপনি বিভিন্ন টেবিলের এক্স মান গণনা বজায় রেখে এই ক্যোয়ারীটি গতি বাড়িয়ে তুলতে পারেন, উদাহরণস্বরূপ table_name_x_counts (x integer not null, x_count int not null), ট্রিগার ব্যবহার করে। তবে আপনার লেখার পারফরম্যান্স ক্ষতিগ্রস্থ হবে এবং আপনি যদি xএকক লেনদেনে একাধিক মান আপডেট করেন তবে সম্ভাব্য অচলাবস্থা এড়াতে আপনার কিছু স্পষ্ট করে এই কাজটি করা দরকার।


0

আমি একই উত্তরটিও সন্ধান করছিলাম, কারণ এক সময় আমার সীমা / অফসেটের সাথে স্বতন্ত্র মানগুলির সাথে মোট_সংখ্যার প্রয়োজন ছিল ।

কারণ এটি করা সামান্য কৌশল- সীমা / অফসেট সহ স্বতন্ত্র মানগুলির সাথে মোট গণনা পাওয়া। সাধারণত সীমা / অফসেট সহ মোট গণনা পাওয়া শক্ত। অবশেষে আমি করার উপায়টি পেয়েছি -

SELECT DISTINCT COUNT(*) OVER() as total_count, * FROM table_name limit 2 offset 0;

অনুসন্ধানের পারফরম্যান্সও বেশি high

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