20 এম সারিতে পোস্টগ্রিসে 'সর্বশেষ' ক্যোয়ারী অনুকূলিতকরণ


10

আমার টেবিলটি নীচে দেখায়:

    Column             |    Type           |    
-----------------------+-------------------+
 id                    | integer           | 
 source_id             | integer           | 
 timestamp             | integer           | 
 observation_timestamp | integer           | 
 value                 | double precision  | 

সূচকগুলি সোর্স_আইডি, টাইমস্ট্যাম্প এবং টাইমস্ট্যাম্প এবং আইডি ( CREATE INDEX timeseries_id_timestamp_combo_idx ON timeseries (id, timeseries DESC NULLS LAST)) এর কম্বোতে বিদ্যমান

এটিতে 20M সারি রয়েছে (ঠিক আছে, 120M আছে, তবে উত্স_আইড = 1 সহ 20 এম)। এর timestampবিবিধ পরিবর্তনের জন্য অনেকগুলি এন্ট্রি রয়েছে observation_timestampযা রিপোর্ট বা পর্যবেক্ষণে valueঘটেছে তা বর্ণনা timestampকরে observation_timestamp। উদাহরণস্বরূপ, আজ সকাল 12 টা বেজে গেছে তাপমাত্রা আগামীকাল দুপুর ২ টা থেকে।

আদর্শভাবে এই টেবিলটি কয়েকটি কাজ ভাল করে:

  • ব্যাচ নতুন এন্ট্রি সন্নিবেশ করছে, কখনও কখনও একবারে 100 কে
  • টাইমারেঞ্জগুলির জন্য পর্যবেক্ষণ করা ডেটা নির্বাচন করা ("জানুয়ারীর জন্য মার্চ পর্যন্ত তাপমাত্রার পূর্বাভাস কী")
  • নির্দিষ্ট বিন্দু থেকে পর্যবেক্ষণ অনুযায়ী টাইমারেঞ্জের জন্য পর্যবেক্ষণ করা ডেটা নির্বাচন করা ("আমরা 1 লা নভেম্বর আমরা যেমন ভেবেছিলাম জানুয়ারীর জন্য তাপমাত্রার পূর্বাভাসগুলি জানুয়ারী পর্যন্ত রয়েছে")

দ্বিতীয়টি হ'ল এই প্রশ্নের কেন্দ্রে।

টেবিলের ডেটা নীচের মত দেখতে হবে

id  source_id   timestamp   observation_timestamp   value
1   1           1531084900  1531083900              9999
2   1           1531084900  1531082900              1111
3   1           1531085900  1531083900              8888
4   1           1531085900  1531082900              7777
5   1           1531086900  1531082900              5555

এবং ক্যোয়ারীর একটি আউটপুট নীচের মত দেখতে হবে (কেবলমাত্র সর্বশেষ পর্যবেক্ষণ_টাইমস্ট্যাম্পের সারি উপস্থাপিত হয়েছে)

id  source_id   timestamp   observation_timestamp   value
1   1           1531084900  1531083900              9999
3   1           1531085900  1531083900              8888
5   1           1531086900  1531082900              5555

আমি ইতিমধ্যে এই কোয়েরিগুলি অনুকূলকরণের জন্য ইতিমধ্যে কিছু উপাদানগুলির সাথে পরামর্শ করেছি

... সীমিত সাফল্য সহ।

আমি timestampএটির সাথে একটি পৃথক টেবিল তৈরি করার বিষয়টি বিবেচনা করেছি যাতে দীর্ঘস্থায়ীভাবে উল্লেখ করা সহজ, তবে তাদের তুলনামূলকভাবে উচ্চ কার্ডিনালটির কারণে আমি সন্দেহ করি যে তারা আমাকে সহায়তা করবে কিনা - অতিরিক্তভাবে আমি উদ্বিগ্ন যে এটি সম্পাদনে বাধা সৃষ্টি করবে batch inserting new entries


আমি তিনটি প্রশ্নের দিকে তাকিয়ে রয়েছি, এবং তারা সবাই আমাকে খারাপ অভিনয় দেয়

  • LATERAL যোগদানের সাথে পুনরাবৃত্তির CTE
  • উইন্ডো ফাংশন
  • ডিস্টিন্ট চালু

(আমি জানি যে তারা এই মুহূর্তে বেশিরভাগ একই জিনিস করেন না, তবে তারা যতদূর দেখছেন অনুসন্ধানের ধরণের ভাল চিত্র হিসাবে কাজ করে))

LATERAL যোগদানের সাথে পুনরাবৃত্তির CTE

WITH RECURSIVE cte AS (
    (
        SELECT ts
        FROM timeseries ts
        WHERE source_id = 1
        ORDER BY id, "timestamp" DESC NULLS LAST
        LIMIT 1
    )
    UNION ALL
    SELECT (
        SELECT ts1
        FROM timeseries ts1
        WHERE id > (c.ts).id
        AND source_id = 1
        ORDER BY id, "timestamp" DESC NULLS LAST
        LIMIT 1
    )
    FROM cte c
    WHERE (c.ts).id IS NOT NULL
)
SELECT (ts).*
FROM cte
WHERE (ts).id IS NOT NULL
ORDER BY (ts).id;

কর্মক্ষমতা:

Sort  (cost=164999681.98..164999682.23 rows=100 width=28)
  Sort Key: ((cte.ts).id)
  CTE cte
    ->  Recursive Union  (cost=1653078.24..164999676.64 rows=101 width=52)
          ->  Subquery Scan on *SELECT* 1  (cost=1653078.24..1653078.26 rows=1 width=52)
                ->  Limit  (cost=1653078.24..1653078.25 rows=1 width=60)
                      ->  Sort  (cost=1653078.24..1702109.00 rows=19612304 width=60)
                            Sort Key: ts.id, ts.timestamp DESC NULLS LAST
                            ->  Bitmap Heap Scan on timeseries ts  (cost=372587.92..1555016.72 rows=19612304 width=60)
                                  Recheck Cond: (source_id = 1)
                                  ->  Bitmap Index Scan on ix_timeseries_source_id  (cost=0.00..367684.85 rows=19612304 width=0)
                                        Index Cond: (source_id = 1)
          ->  WorkTable Scan on cte c  (cost=0.00..16334659.64 rows=10 width=32)
                Filter: ((ts).id IS NOT NULL)
                SubPlan 1
                  ->  Limit  (cost=1633465.94..1633465.94 rows=1 width=60)
                        ->  Sort  (cost=1633465.94..1649809.53 rows=6537435 width=60)
                              Sort Key: ts1.id, ts1.timestamp DESC NULLS LAST
                              ->  Bitmap Heap Scan on timeseries ts1  (cost=369319.21..1600778.77 rows=6537435 width=60)
                                    Recheck Cond: (source_id = 1)
                                    Filter: (id > (c.ts).id)
                                    ->  Bitmap Index Scan on ix_timeseries_source_id  (cost=0.00..367684.85 rows=19612304 width=0)
                                          Index Cond: (source_id = 1)
  ->  CTE Scan on cte  (cost=0.00..2.02 rows=100 width=28)
        Filter: ((ts).id IS NOT NULL)

(শুধুমাত্র EXPLAIN, EXPLAIN ANALYZEসম্পূর্ণ করতে পারেনি, গ্রহণ> সম্পূর্ণ প্রশ্নের 24 ঘন্টায়)

উইন্ডো ফাংশন

WITH summary AS (
  SELECT ts.id, ts.source_id, ts.value,
    ROW_NUMBER() OVER(PARTITION BY ts.timestamp ORDER BY ts.observation_timestamp DESC) AS rn
  FROM timeseries ts
  WHERE source_id = 1
)
SELECT s.*
FROM summary s
WHERE s.rn = 1;

কর্মক্ষমতা:

CTE Scan on summary s  (cost=5530627.97..5971995.66 rows=98082 width=24) (actual time=150368.441..226331.286 rows=88404 loops=1)
  Filter: (rn = 1)
  Rows Removed by Filter: 20673704
  CTE summary
    ->  WindowAgg  (cost=5138301.13..5530627.97 rows=19616342 width=32) (actual time=150368.429..171189.504 rows=20762108 loops=1)
          ->  Sort  (cost=5138301.13..5187341.98 rows=19616342 width=24) (actual time=150368.405..165390.033 rows=20762108 loops=1)
                Sort Key: ts.timestamp, ts.observation_timestamp DESC
                Sort Method: external merge  Disk: 689752kB
                ->  Bitmap Heap Scan on timeseries ts  (cost=372675.22..1555347.49 rows=19616342 width=24) (actual time=2767.542..50399.741 rows=20762108 loops=1)
                      Recheck Cond: (source_id = 1)
                      Rows Removed by Index Recheck: 217784
                      Heap Blocks: exact=48415 lossy=106652
                      ->  Bitmap Index Scan on ix_timeseries_source_id  (cost=0.00..367771.13 rows=19616342 width=0) (actual time=2757.245..2757.245 rows=20762630 loops=1)
                            Index Cond: (source_id = 1)
Planning time: 0.186 ms
Execution time: 234883.090 ms

ডিস্টিন্ট চালু

SELECT DISTINCT ON (timestamp) *
FROM timeseries
WHERE source_id = 1
ORDER BY timestamp, observation_timestamp DESC;

কর্মক্ষমতা:

Unique  (cost=5339449.63..5437531.34 rows=15991 width=28) (actual time=112653.438..121397.944 rows=88404 loops=1)
  ->  Sort  (cost=5339449.63..5388490.48 rows=19616342 width=28) (actual time=112653.437..120175.512 rows=20762108 loops=1)
        Sort Key: timestamp, observation_timestamp DESC
        Sort Method: external merge  Disk: 770888kB
        ->  Bitmap Heap Scan on timeseries  (cost=372675.22..1555347.49 rows=19616342 width=28) (actual time=2091.585..56109.942 rows=20762108 loops=1)
              Recheck Cond: (source_id = 1)
              Rows Removed by Index Recheck: 217784
              Heap Blocks: exact=48415 lossy=106652
              ->  Bitmap Index Scan on ix_timeseries_source_id  (cost=0.00..367771.13 rows=19616342 width=0) (actual time=2080.054..2080.054 rows=20762630 loops=1)
                    Index Cond: (source_id = 1)
Planning time: 0.132 ms
Execution time: 161651.006 ms

আমার ডেটা কীভাবে গঠন করা উচিত, এমন স্ক্যানগুলি থাকা উচিত যা সেখানে হওয়া উচিত নয়, সাধারণত এই প্রশ্নগুলি ~ 1s (120s এর পরিবর্তে) এ পাওয়া সম্ভব?

আমি যে ফলাফল চেয়েছিলাম তা পেতে কি ডেটা জিজ্ঞাসা করার আলাদা উপায় আছে?

যদি তা না হয় তবে আমার কী আলাদা অবকাঠামো / আর্কিটেকচারের দিকে নজর দেওয়া উচিত?


আপনি যা চান তা হ'ল আলগা-সূচক স্ক্যান বা স্কিপ স্ক্যান। যারা শীঘ্রই আসছে। আপনি যদি এটির সাথে ঝামেলা করতে চান তবে আপনি এখন প্যাচটি প্রয়োগ করতে পারেন postgresql-archive.org/Index-Skip-Scan-td6025532.html এটি সবেমাত্র এক মাস বয়সী = পি
ইভান ক্যারল

লিভিন 'প্রান্তে @ ইভানক্রোল = পি - এটি আমার পক্ষে খুব তাড়াতাড়ি মনে হয়, বিবেচনা করে আমি অ্যাজুরে পোস্টগ্র্রেস ব্যবহারযোগ্য এমনকি না করতে পারছি।
পেপিজান শোইন

অনুগ্রহ করে লিমিটেডগুলি ছাড়াই বিশ্লেষণ বিশ্লেষণের পরিকল্পনাগুলি দেখান (যেহেতু এটিই অনুকূলিত করা প্রয়োজন) তবে আমার প্রথম উত্তরে আমি প্রস্তাবিত পরিবর্তনগুলি দিয়ে recommended তবে লিমিটেডগুলি ছাড়াই, আমি মনে করি আপনি একটি অসম্ভব পরিমাণ কাজ ~ 1s এর জন্য করতে বলছেন। হতে পারে আপনি কিছু জিনিস প্রাক্পম্প্ট করতে পারেন।
jjanes

@ জাজানস একেবারে - এই পরামর্শের জন্য আপনাকে ধন্যবাদ। আমি সরিয়ে দিয়েছি LIMITপ্রশ্ন এখন, এবং আউটপুট যোগ EXPLAIN ANALYZE(শুধুমাত্র EXPLAINউপর recursiveঅংশ যদিও)
Pepijn Schoen

উত্তর:


1

আপনার পুনরাবৃত্তির সিটিই ক্যোয়ারীর সাথে ফাইনালটি ORDER BY (ts).idঅপ্রয়োজনীয় কারণ সিটিই স্বয়ংক্রিয়ভাবে সেগুলি তাদের তৈরি করে। এটিকে সরিয়ে ফেললে ক্যোয়ারীটি আরও দ্রুততর হওয়া উচিত, এটি কেবল ৫০০ টি দূরে ফেলে দেওয়ার জন্য কেবল 20,180,572 সারি তৈরি করার চেয়ে তাড়াতাড়ি থামতে পারে। এছাড়াও, সূচকটি তৈরি করার সময় (source_id, id, timestamp desc nulls last)এটি আরও উন্নত করা উচিত।

অন্য দুটি প্রশ্নের জন্য, work_mem পর্যাপ্ত পরিমাণে বাড়ানো যে বিটম্যাপগুলি মেমরির সাথে ফিট করে (ক্ষতিকারক হিপ ব্লকগুলি থেকে মুক্তি পেতে) কিছুকে সহায়তা করবে। তবে কাস্টম সূচকগুলির মতো তত বেশি নয় যেমন (source_id, "timestamp", observation_timestamp DESC)কেবলমাত্র সূচি স্ক্যানগুলির জন্য বা আরও ভাল (source_id, "timestamp", observation_timestamp DESC, value, id)


পরামর্শ দেওয়ার জন্য আপনাকে ধন্যবাদ - আপনার পরামর্শ মতো আমি অবশ্যই কাস্টম ইনডেক্সিংয়ে নজর দেব। LIMIT 500আমাকে আউটপুট সীমিত করতে জন্য বোঝানো হয়, কিন্তু উৎপাদন কোডে এই ঘটতে না। আমি প্রতিবিম্বিত করতে আমার পোস্ট সম্পাদনা করব।
পেপিজান শোইন

লিমিটের অনুপস্থিতিতে, সূচিগুলি অনেক কম কার্যকর হতে পারে। তবে এখনও চেষ্টা করে দেখুন।
jjanes

আপনি সঠিক - LIMITআপনার পরামর্শ অনুসারে, বর্তমানে মৃত্যুদণ্ড কার্যকর হয় 356.482 ms( Index Scan using ix_timeseries_source_id_timestamp_observation_timestamp on timeseries (cost=0.57..62573201.42 rows=18333374 width=28) (actual time=174.098..356.097 rows=2995 loops=1)) তবে LIMITআগের মতো না করে। আমি কীভাবে Index Scanসেই ক্ষেত্রেও কীভাবে উপার্জন করব Bitmap Index/Heap Scan?
পেপিজেন শোয়েন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.