পোস্টগ্রিএসকিউএল সারণি সারির আকার পরিমাপ করুন


83

আমার একটি পোস্টগ্রিএসকিউএল টেবিল রয়েছে। select *খুব ধীর এবং select idসুন্দর এবং দ্রুত। আমি মনে করি এটি হতে পারে যে সারিটির আকার খুব বড় এবং এটি পরিবহনে কিছুটা সময় নিচ্ছে, বা এটি অন্য কোনও কারণ হতে পারে।

আমার সমস্ত ক্ষেত্রের (বা প্রায় সবগুলি) দরকার, সুতরাং কেবলমাত্র একটি উপসেট নির্বাচন করা দ্রুত সমাধান নয়। আমি যে ক্ষেত্রগুলি চাই তা নির্বাচন করা এখনও ধীর।

এখানে আমার টেবিল স্কিমা নামগুলি বিয়োগ:

integer                  | not null default nextval('core_page_id_seq'::regclass)
character varying(255)   | not null
character varying(64)    | not null
text                     | default '{}'::text
character varying(255)   | 
integer                  | not null default 0
text                     | default '{}'::text
text                     | 
timestamp with time zone | 
integer                  | 
timestamp with time zone | 
integer                  | 

পাঠ্য ক্ষেত্রের আকার কোনও আকার হতে পারে। তবে এখনও, সবচেয়ে খারাপ ক্ষেত্রে কয়েক কিলোবাইটের বেশি নয়।

প্রশ্নাবলি

  1. এ সম্পর্কে এমন কিছু আছে যা চিৎকার করে 'পাগল অক্ষম'?
  2. আমাকে এটির ডিবাগ করতে সহায়তা করার জন্য পোস্টগ্রিস কমান্ড-লাইনে পৃষ্ঠার আকার পরিমাপ করার কোনও উপায় আছে কি?

আসলে ... কলামগুলির একটি হ'ল 11 এমবি। এটি আমার মনে হয় এটি ব্যাখ্যা করবে। তাহলে কি উপায় না করে length(*)বরং উপায় আছে length(field)? আমি জানি এটি অক্ষর বাইট নয় তবে আমার কেবল একটি প্রায় মান প্রয়োজন।
জো

উত্তর:


101

Q2 এর: way to measure page size

PostgreSQL অনেকগুলি ডাটাবেস অবজেক্ট সাইজ ফাংশন সরবরাহ করে । আমি এই ক্যোয়ারিতে সবচেয়ে আকর্ষণীয় বিষয়বস্তু নিয়েছি এবং নীচে কিছু পরিসংখ্যান অ্যাক্সেস ফাংশন যুক্ত করেছি । (অতিরিক্ত মডিউল pgstattuple আরও কার্যকর ফাংশন সরবরাহ করে, তবুও))

এটি দেখিয়ে যাচ্ছে যে "একটি সারির আকার" পরিমাপের বিভিন্ন পদ্ধতি খুব ভিন্ন ফলাফলের দিকে নিয়ে যায়। এটি সমস্ত কি আপনি সঠিকভাবে পরিমাপ করতে চান তার উপর নির্ভর করে।

এই প্রশ্নের সাথে প্রয়োজন Postgres 9.3 বা পরবর্তী । পুরানো সংস্করণগুলির জন্য নীচে দেখুন।

প্রতিটি সারির জন্য বানান গণনা এড়ানোর জন্য, VALUESএকটি LATERALsubquery একটি এক্সপ্রেশন ব্যবহার ।

public.tblআপনার সারিগুলির আকার সম্পর্কে সংগৃহীত পরিসংখ্যানগুলির একটি কমপ্যাক্ট ভিউ পেতে আপনার allyচ্ছিকভাবে স্কিমা-যোগ্য টেবিল নাম দিয়ে (দু'বার) প্রতিস্থাপন করুন । আপনি এটি বারবার ব্যবহারের জন্য একটি plpgsql ফাংশনে আবদ্ধ করতে পারেন, টেবিলের নামটিকে প্যারামিটার হিসাবে ব্যবহার করুন এবং ব্যবহার করুন EXECUTE...

SELECT l.metric, l.nr AS "bytes/ct"
     , CASE WHEN is_size THEN pg_size_pretty(nr) END AS bytes_pretty
     , CASE WHEN is_size THEN nr / NULLIF(x.ct, 0) END AS bytes_per_row
FROM  (
   SELECT min(tableoid)        AS tbl      -- = 'public.tbl'::regclass::oid
        , count(*)             AS ct
        , sum(length(t::text)) AS txt_len  -- length in characters
   FROM   public.tbl t                     -- provide table name *once*
   ) x
 , LATERAL (
   VALUES
      (true , 'core_relation_size'               , pg_relation_size(tbl))
    , (true , 'visibility_map'                   , pg_relation_size(tbl, 'vm'))
    , (true , 'free_space_map'                   , pg_relation_size(tbl, 'fsm'))
    , (true , 'table_size_incl_toast'            , pg_table_size(tbl))
    , (true , 'indexes_size'                     , pg_indexes_size(tbl))
    , (true , 'total_size_incl_toast_and_indexes', pg_total_relation_size(tbl))
    , (true , 'live_rows_in_text_representation' , txt_len)
    , (false, '------------------------------'   , NULL)
    , (false, 'row_count'                        , ct)
    , (false, 'live_tuples'                      , pg_stat_get_live_tuples(tbl))
    , (false, 'dead_tuples'                      , pg_stat_get_dead_tuples(tbl))
   ) l(is_size, metric, nr);

ফলাফল:

              মেট্রিক | বাইটস / সিটি | bytes_ ব্যাখ্যা | bytes_per_row
----------------------------------- + + ---------- + + --- ----------- + + ---------------
 কোর_ রিলেশন_সাইজ | 44138496 | 42 এমবি | 91
 দৃশ্যমানতা_ম্যাপ | 0 | 0 বাইট | 0
 ফ্রি_স্পেস_ম্যাপ | 32768 | 32 কেবি | 0
 টেবিল_সাইজ_ইঙ্কেল_ টোস্ট | 44179456 | 42 এমবি | 91
 সূচি_সাইজ | 33128448 | 32 এমবি | 68
 টোটাল_সাইজ_ইনসিএল_ টোস্ট_অ্যান্ড_ইন্ডেক্সসমূহ | 77307904 | 74 এমবি | 159
 live_rows_in_text_ বিবরণী | 29987360 | 29 এমবি | 62
 ------------------------------ | | |
 সারি_কাউন্ট | 483424 | |
 live_tuples | 483424 | |
 মৃত_টুপলস | 2677 | |

পুরানো সংস্করণগুলির জন্য (9.2 বা তার বেশি বয়সে পোস্টগ্রিজ):

WITH x AS (
   SELECT count(*)               AS ct
        , sum(length(t::text))   AS txt_len  -- length in characters
        , 'public.tbl'::regclass AS tbl      -- provide table name as string
   FROM   public.tbl t                       -- provide table name as name
   ), y AS (
   SELECT ARRAY [pg_relation_size(tbl)
               , pg_relation_size(tbl, 'vm')
               , pg_relation_size(tbl, 'fsm')
               , pg_table_size(tbl)
               , pg_indexes_size(tbl)
               , pg_total_relation_size(tbl)
               , txt_len
             ] AS val
        , ARRAY ['core_relation_size'
               , 'visibility_map'
               , 'free_space_map'
               , 'table_size_incl_toast'
               , 'indexes_size'
               , 'total_size_incl_toast_and_indexes'
               , 'live_rows_in_text_representation'
             ] AS name
   FROM   x
   )
SELECT unnest(name)                AS metric
     , unnest(val)                 AS "bytes/ct"
     , pg_size_pretty(unnest(val)) AS bytes_pretty
     , unnest(val) / NULLIF(ct, 0) AS bytes_per_row
FROM   x, y

UNION ALL SELECT '------------------------------', NULL, NULL, NULL
UNION ALL SELECT 'row_count', ct, NULL, NULL FROM x
UNION ALL SELECT 'live_tuples', pg_stat_get_live_tuples(tbl), NULL, NULL FROM x
UNION ALL SELECT 'dead_tuples', pg_stat_get_dead_tuples(tbl), NULL, NULL FROM x;

একই ফলাফল।

চতুর্থাংশ 1: anything inefficient?

সারি প্রতি কিছু বাইট সংরক্ষণের জন্য আপনি কলাম ক্রমটি অনুকূল করতে পারেন, বর্তমানে অ্যালাইনমেন্ট প্যাডিংয়ে নষ্ট:

integer                  | not null default nextval('core_page_id_seq'::regclass)
integer                  | not null default 0
character varying(255)   | not null
character varying(64)    | not null
text                     | default '{}'::text
character varying(255)   | 
text                     | default '{}'::text
text                     |
timestamp with time zone |
timestamp with time zone |
integer                  |
integer                  |

এটি প্রতি সারিতে 8 এবং 18 বাইটের মধ্যে সঞ্চয় করে। আমি এটিকে "কলাম টেট্রিস" বলি । বিবরণ:

এছাড়াও বিবেচনা করুন:


আপনার স্নিপেটটি 9.3 পূর্বের সারণীটি খালি থাকলে শূন্য দ্বারা একটি বিভাগ ফেলে দেয়। আমি আসলে 9.3+ সংস্করণটি ব্যবহার করতে চেয়েছিলাম, তবে ভুল করে ভুলটি বেছে নিয়েছি এবং এটি ঠিক করতে কয়েক ঘন্টা ব্যয় করতে হয়েছিল ... এখন আমি সমস্ত সময় নষ্ট হতে দিতে পারি না। , unnest(val) / ctদ্বারা প্রতিস্থাপন , (LEAST(unnest(val), unnest(val) * ct)) / (ct - 1 + sign(ct))এবং এটি নিক্ষেপ করবে না। যুক্তিটি হ'ল, যখন ctহয় 0, valপ্রতিস্থাপিত হবে 0এবং এর দ্বারা প্রতিস্থাপিত ctহবে 1
গুইরিটার

1
@ গুয়িটার: দেখানোর জন্য ধন্যবাদ যদিও আমি একটি সহজ ফিক্স প্রয়োগ করেছি। এছাড়াও থাকাকালীন কিছু সাধারণ আপডেট - তবে কোয়েরিটি একই রয়েছে।
এরউন ব্র্যান্ডস্টেটর

35

সম্পূর্ণ সারিটির পাঠ্য উপস্থাপনার দৈর্ঘ্য জিজ্ঞাসা করে টোস্টের সম্পাদনা সামগ্রী সহ একটি সারির আকারের প্রায় অনুমান করা সহজ:

SELECT octet_length(t.*::text) FROM tablename AS t WHERE primary_key=:value;

এটি কার্যকর করার সময় ক্লায়েন্ট-সাইড পুনরুদ্ধার করা হবে এমন বাইটের সংখ্যার নিকটতম আনুমানিক:

SELECT * FROM tablename WHERE primary_key=:value;

... ধরে নিচ্ছি যে ক্যোয়ারের কলকারী পাঠ্য বিন্যাসে ফলাফলের জন্য অনুরোধ করছে, যা বেশিরভাগ প্রোগ্রামই করেন (বাইনারি ফর্ম্যাটটি সম্ভব তবে বেশিরভাগ ক্ষেত্রেই সমস্যাটি মূল্যহীন নয়)।

N"বৃহত্তম-ইন-পাঠ্য" সারিগুলি সনাক্ত করতে একই কৌশল প্রয়োগ করা যেতে পারে tablename:

SELECT primary_key, octet_length(t.*::text) FROM tablename AS t
   ORDER BY 2 DESC LIMIT :N;

বড় ডেটার সাথে কাজ করার সময় দ্রুত কিছুটা অনুমান করার দুর্দান্ত উপায় (উদাহরণস্বরূপ সারি আকারের বেশিরভাগটি ভেরিয়েবল-দৈর্ঘ্যের টোস্ট-সঞ্চিত কলামগুলিতে থাকে), ভাল ধারণা!
fgblomqvist

14

কিছু ঘটনা ঘটতে পারে। সাধারণভাবে, আমি সন্দেহ করি যে দৈর্ঘ্য হচ্ছে প্রক্সিমাল সমস্যা। পরিবর্তে আপনার সন্দেহ হয় আপনার দৈর্ঘ্য সম্পর্কিত সমস্যা আছে।

আপনি বলছেন পাঠ্য ক্ষেত্রগুলি কয়েক কে-তে উঠতে পারে। একটি সারি মূল স্টোরেজে 8 কের বেশি যেতে পারে না এবং সম্ভবত আপনার বৃহত পাঠ্য ক্ষেত্রগুলি টুস্ট করা হয়েছে , বা মূল স্টোরেজ থেকে আলাদা ফাইলগুলিতে বর্ধিত স্টোরেজে সরানো হয়েছে । এটি আপনার মূল স্টোরেজটিকে দ্রুত করে তোলে (তাই আইডি নির্বাচন করুন আসলে আরও দ্রুত কারণ অ্যাক্সেসের জন্য কম ডিস্ক পৃষ্ঠাগুলি থাকে) তবে নির্বাচন করুন * ধীর হয়ে যায় কারণ আরও র্যান্ডম আই / ও রয়েছে।

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

প্রথম কাজটি আমি করণে দেখাব তা হ'ল কম সারি নির্বাচন করা এবং এটি সাহায্য করে কিনা তা দেখুন। যদি এটি কাজ করে তবে আপনি সার্ভারে আরও র‌্যাম যুক্ত করার চেষ্টা করতে পারেন, তবে পরিকল্পনার পরিবর্তনগুলি এবং ক্যাশেটি প্রথমে মিস করা না হওয়ায় আমি শুরু করে দেখতে পারি যেখানে কর্মক্ষমতা হ্রাস পাচ্ছে।


4

উপরে উল্লিখিত ডাটাবেস অবজেক্ট সাইজের ফাংশনগুলি ব্যবহার করে :

SELECT primary_key, pg_column_size(tablename.*) FROM tablename;


প্রতিশ্রুতিবদ্ধ লাগছিল, তবে কোনও কারণে এটি আমার ক্ষেত্রে কার্যকর হয় না। pg_column_size (টেবিলের নাম.বিগ_ক্লোনম) pg_column_size (টেবিলের নাম। *) এর মান অতিক্রম করেছে
লিনাক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.