পড়ার পারফরম্যান্সের জন্য পোস্টগ্রিএসকিউএল কনফিগার করছে


39

আমাদের সিস্টেম প্রচুর ডেটা লিখায় (বিগ ডেটা সিস্টেমের ধরণের)। লেখার পারফরম্যান্স আমাদের প্রয়োজনের জন্য যথেষ্ট ভাল তবে পড়ার পারফরম্যান্সটি সত্যই খুব ধীর।

প্রাথমিক কী (সীমাবদ্ধতা) কাঠামোটি আমাদের সমস্ত সারণীর জন্য সমান:

timestamp(Timestamp) ; index(smallint) ; key(integer).

একটি সারণীতে কয়েক মিলিয়ন সারি, এমনকি কয়েক বিলিয়ন সারি থাকতে পারে এবং একটি পঠন অনুরোধ সাধারণত একটি নির্দিষ্ট সময়কালের (টাইমস্ট্যাম্প / সূচক) এবং ট্যাগের জন্য থাকে। প্রায় 200k লাইনের প্রত্যাবর্তনকারী একটি কোয়েরি থাকা সাধারণ common বর্তমানে, আমরা প্রতি সেকেন্ডে প্রায় 15 ক লাইন পড়তে পারি তবে আমাদের 10 গুণ দ্রুত হওয়া দরকার। এটি কি সম্ভব এবং যদি তাই হয় তবে কীভাবে?

দ্রষ্টব্য: পোস্টগ্রিএসকিউএল আমাদের সফ্টওয়্যারটির সাথে প্যাকেজড, তাই হার্ডওয়্যারটি একটি ক্লায়েন্ট থেকে অন্য ক্লায়েন্টের থেকে আলাদা।

এটি পরীক্ষার জন্য ব্যবহৃত একটি ভিএম। ভিএম এর হোস্টটি উইন্ডোজ সার্ভার 2008 আর 2 এক্স 64 যার 24.0 গিগাবাইট র‌্যাম রয়েছে।

সার্ভার স্পেস (ভার্চুয়াল মেশিন ভিএমওয়্যার)

Server 2008 R2 x64
2.00 GB of memory
Intel Xeon W3520 @ 2.67GHz (2 cores)

postgresql.conf optimisations

shared_buffers = 512MB (default: 32MB)
effective_cache_size = 1024MB (default: 128MB)
checkpoint_segment = 32 (default: 3)
checkpoint_completion_target = 0.9 (default: 0.5)
default_statistics_target = 1000 (default: 100)
work_mem = 100MB (default: 1MB)
maintainance_work_mem = 256MB (default: 16MB)

সারণি সংজ্ঞা

CREATE TABLE "AnalogTransition"
(
  "KeyTag" integer NOT NULL,
  "Timestamp" timestamp with time zone NOT NULL,
  "TimestampQuality" smallint,
  "TimestampIndex" smallint NOT NULL,
  "Value" numeric,
  "Quality" boolean,
  "QualityFlags" smallint,
  "UpdateTimestamp" timestamp without time zone, -- (UTC)
  CONSTRAINT "PK_AnalogTransition" PRIMARY KEY ("Timestamp" , "TimestampIndex" , "KeyTag" ),
  CONSTRAINT "FK_AnalogTransition_Tag" FOREIGN KEY ("KeyTag")
      REFERENCES "Tag" ("Key") MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
  OIDS=FALSE,
  autovacuum_enabled=true
);

প্রশ্ন

ক্যোয়ারীটি পিজিএডমিন 3 এ চালিত হতে প্রায় 30 সেকেন্ড সময় নেয়, তবে আমরা যদি সম্ভব হয় তবে 5 সেকেন্ডের নীচে একই ফল পেতে চাই।

SELECT 
    "AnalogTransition"."KeyTag", 
    "AnalogTransition"."Timestamp" AT TIME ZONE 'UTC', 
    "AnalogTransition"."TimestampQuality", 
    "AnalogTransition"."TimestampIndex", 
    "AnalogTransition"."Value", 
    "AnalogTransition"."Quality", 
    "AnalogTransition"."QualityFlags", 
    "AnalogTransition"."UpdateTimestamp"
FROM "AnalogTransition"
WHERE "AnalogTransition"."Timestamp" >= '2013-05-16 00:00:00.000' AND "AnalogTransition"."Timestamp" <= '2013-05-17 00:00:00.00' AND ("AnalogTransition"."KeyTag" = 56 OR "AnalogTransition"."KeyTag" = 57 OR "AnalogTransition"."KeyTag" = 58 OR "AnalogTransition"."KeyTag" = 59 OR "AnalogTransition"."KeyTag" = 60)
ORDER BY "AnalogTransition"."Timestamp" DESC, "AnalogTransition"."TimestampIndex" DESC
LIMIT 500000;

ব্যাখ্যা কর…

"Limit  (cost=0.00..125668.31 rows=500000 width=33) (actual time=2.193..3241.319 rows=500000 loops=1)"
"  Buffers: shared hit=190147"
"  ->  Index Scan Backward using "PK_AnalogTransition" on "AnalogTransition"  (cost=0.00..389244.53 rows=1548698 width=33) (actual time=2.187..1893.283 rows=500000 loops=1)"
"        Index Cond: (("Timestamp" >= '2013-05-16 01:00:00-04'::timestamp with time zone) AND ("Timestamp" <= '2013-05-16 15:00:00-04'::timestamp with time zone))"
"        Filter: (("KeyTag" = 56) OR ("KeyTag" = 57) OR ("KeyTag" = 58) OR ("KeyTag" = 59) OR ("KeyTag" = 60))"
"        Buffers: shared hit=190147"
"Total runtime: 3863.028 ms"

2 ব্যাখ্যা করুন

আমার সর্বশেষ পরীক্ষায়, আমার ডেটা নির্বাচন করতে 7 মিনিট সময় লেগেছে! নিচে দেখ:

"Limit  (cost=0.00..313554.08 rows=250001 width=35) (actual time=0.040..410721.033 rows=250001 loops=1)"
"  ->  Index Scan using "PK_AnalogTransition" on "AnalogTransition"  (cost=0.00..971400.46 rows=774511 width=35) (actual time=0.037..410088.960 rows=250001 loops=1)"
"        Index Cond: (("Timestamp" >= '2013-05-22 20:00:00-04'::timestamp with time zone) AND ("Timestamp" <= '2013-05-24 20:00:00-04'::timestamp with time zone) AND ("KeyTag" = 16))"
"Total runtime: 411044.175 ms"

উত্তর:


52

ডেটা প্রান্তিককরণ এবং স্টোরেজ আকার

প্রকৃতপক্ষে, টুপল প্রতি ওভারহেডটি আইটেম পয়েন্টারটির জন্য টিউপল শিরোনামের জন্য 4 বাইট প্লাস 4 বাইট হয়।
এই সম্পর্কিত উত্তরের গণনায় আরও বিশদ:

এসও সম্পর্কিত এই সম্পর্কিত তথ্যে ডেটা সারিবদ্ধকরণ এবং প্যাডিংয়ের মূল বিষয়গুলি:

প্রাথমিক কীটির জন্য আমাদের তিনটি কলাম রয়েছে:

PRIMARY KEY ("Timestamp" , "TimestampIndex" , "KeyTag")

"Timestamp"      timestamp (8 bytes)
"TimestampIndex" smallint  (2 bytes)
"KeyTag"         integer   (4 bytes)

ফলাফল স্বরূপ:

 পৃষ্ঠা শিরোনামে 4 বাইট আইটেম পয়েন্টার (8 বাইটের একাধিকের জন্য গণনা করা হচ্ছে না)
---
টিপল শিরোলেখের জন্য 23 বাইট
 ডেটা সারিবদ্ধকরণের জন্য 1 বাইট প্যাডিং (বা NULL বিটম্যাপ)
 8 টি বাইটস "টাইমস্ট্যাম্প"
 2 টাইম "টাইমস্ট্যাম্প ইন্ডেক্স"
 ডেটা সারিবদ্ধকরণের জন্য 2 বাইট প্যাডিং
 4 বাইট "কীট্যাগ" 
 নিকটতম একাধিক 8 বাইটে প্যাডিং
-----
টুপল প্রতি 44 বাইট

এই সম্পর্কিত উত্তরে বস্তুর আকার পরিমাপ করা সম্পর্কে আরও:

বহু বহু কলাম সূচীতে কলামগুলির ক্রম

বুঝতে এই দুটি প্রশ্ন এবং উত্তর পড়ুন:

আপনার সূচকের (প্রাথমিক কী) যেভাবে রয়েছে, আপনি বিশেষতঃ আবেদনকারী, কোনও বাছাইকারী পদক্ষেপ ছাড়াই সারিগুলি পুনরুদ্ধার করতে পারেন LIMIT। তবে সারিগুলি পুনরুদ্ধার করা অত্যন্ত ব্যয়বহুল বলে মনে হচ্ছে।

সাধারণত, একটি বহু-কলাম সূচীতে, "সমতা" কলামগুলি প্রথমে এবং "পরিসীমা" কলামগুলি শেষ হওয়া উচিত:

সুতরাং, বিপরীত কলাম অর্ডার সহ একটি অতিরিক্ত সূচক চেষ্টা করুন :

CREATE INDEX analogransition_mult_idx1
   ON "AnalogTransition" ("KeyTag", "TimestampIndex", "Timestamp");

এটি ডেটা বিতরণের উপর নির্ভর করে। তবে millions of row, even billion of rowsএটির সাথে যথেষ্ট দ্রুত হতে পারে।

ডেটা অ্যালাইনমেন্ট এবং প্যাডিংয়ের কারণে টিপল সাইজ 8 বাইট বড়। আপনি যদি এটি সরল সূচক হিসাবে ব্যবহার করেন তবে আপনি তৃতীয় কলামটি ফেলে দেওয়ার চেষ্টা করতে পারেন "Timestamp"। কিছুটা দ্রুত বা নাও হতে পারে (যেহেতু এটি বাছাইয়ে সহায়তা করতে পারে)।

আপনি উভয় সূচী রাখতে চান। বিভিন্ন কারণের উপর নির্ভর করে আপনার মূল সূচকটি পছন্দনীয় হতে পারে - বিশেষত একটি ছোট সাথে LIMIT

অটোভ্যাকুম এবং টেবিলের পরিসংখ্যান

আপনার টেবিলের পরিসংখ্যান আপ টু ডেট হওয়া দরকার। আমি নিশ্চিত যে আপনার অটোভ্যাকুম চলছে।

যেহেতু আপনার টেবিলটি সঠিক ক্যোয়ারী পরিকল্পনার জন্য বিশাল এবং পরিসংখ্যানগুলি গুরুত্বপূর্ণ বলে মনে হচ্ছে, তাই আমি প্রাসঙ্গিক কলামগুলির জন্য পরিসংখ্যানের লক্ষ্যটিকে যথেষ্ট পরিমাণে বাড়িয়ে তুলব :

ALTER TABLE "AnalogTransition" ALTER "Timestamp" SET STATISTICS 1000;

... বা কয়েক বিলিয়ন সারি সহ আরও উচ্চতর। সর্বোচ্চ 10000, ডিফল্ট 100।

জড়িত WHEREবা ORDER BYঅনুচ্ছেদে জড়িত সমস্ত কলামের জন্য এটি করুন । তারপরে দৌড়াও ANALYZE

টেবিল বিন্যাস

এটি উপস্থিত থাকা অবস্থায়, আপনি ডেটা সারিবদ্ধকরণ এবং প্যাডিং সম্পর্কে যা শিখেছেন তা যদি প্রয়োগ করেন তবে এই অনুকূলিত টেবিল বিন্যাসে কিছুটা ডিস্কের জায়গা বাঁচানো উচিত এবং পারফরম্যান্সকে কিছুটা সহায়তা করা উচিত (pk & fk উপেক্ষা করে):

CREATE TABLE "AnalogTransition"(
  "Timestamp" timestamp with time zone NOT NULL,
  "KeyTag" integer NOT NULL,
  "TimestampIndex" smallint NOT NULL,
  "TimestampQuality" smallint,
  "UpdateTimestamp" timestamp without time zone, -- (UTC)
  "QualityFlags" smallint,
  "Quality" boolean,
  "Value" numeric
);

CLUSTER / pg_repack

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

র্যাম

সাধারণত, 2 গিগাবাইট শারীরিক র‍্যাম দ্রুতই কয়েক বিলিয়ন সারিগুলি মোকাবেলা করার পক্ষে যথেষ্ট নয়। আরও র‌্যাম দীর্ঘ পথ যেতে পারে - সাথে অভিযোজিত সেটিং সহ: স্পষ্টতই এর effective_cache_sizeথেকে আরও বড় শুরু করা উচিত।


2
আমি কেবল কীট্যাগে একটি সাধারণ সূচক যুক্ত করেছি এবং এটি এখন বেশ দ্রুত বলে মনে হচ্ছে। আমি ডেটা প্রান্তিককরণ সম্পর্কে আপনার সুপারিশ প্রয়োগ করব। অনেক ধন্যবাদ!
জেপেলিটিয়ার

9

সুতরাং, পরিকল্পনাগুলি থেকে আমি একটি জিনিস দেখতে পাচ্ছি: আপনি সূচকটি ফুলে ফেঁপে উঠেছে (তারপরে অন্তর্নিহিত টেবিলের সাথে) বা কেবল এই ধরণের ক্যোয়ারির জন্য সত্যই ভাল নয় (আমি উপরের আমার সর্বশেষ মন্তব্যে এটি সমাধান করার চেষ্টা করেছি)।

সূচকের এক সারিটিতে 14 বাইট ডেটা রয়েছে (এবং কিছু শিরোনামের জন্য)। এখন, পরিকল্পনায় প্রদত্ত সংখ্যাগুলি থেকে গণনা করা হচ্ছে: আপনি 190147 পৃষ্ঠা থেকে 500,000 সারি পেয়েছেন - তারমানে, প্রতি পৃষ্ঠায় গড়ে 3 টিরও কম সারি, অর্থাৎ 8 কেবি পৃষ্ঠায় প্রায় 37 বাইট। এটি খুব খারাপ অনুপাত, তাই না? যেহেতু সূচকের প্রথম কলামটি Timestampক্ষেত্র এবং এটি ক্যোয়ারিতে একটি ব্যাপ্তি হিসাবে ব্যবহৃত হয়, পরিকল্পনাকারী - এবং করতে পারে - মেলানো সারিগুলি সূচকটি বেছে নিতে পারে। তবে শর্তগুলির TimestampIndexমধ্যে কোনও উল্লেখ নেই WHERE, সুতরাং ফিল্টারিং KeyTagখুব কার্যকর নয় কারণ সেই মানগুলি সূচী পাতায় এলোমেলোভাবে প্রদর্শিত হয়।

সুতরাং, একটি সম্ভাবনা সূচক সংজ্ঞাটি তে পরিবর্তন করা হচ্ছে

CONSTRAINT "PK_AnalogTransition" PRIMARY KEY ("Timestamp", "KeyTag", "TimestampIndex")

(বা, আপনার সিস্টেমের বোঝা দেওয়া হলে, এই সূচকটিকে নতুন হিসাবে তৈরি করুন:

CREATE INDEX CONCURRENTLY "idx_AnalogTransition" 
    ON "AnalogTransition" ("Timestamp", "KeyTag", "TimestampIndex");
  • এটি নিশ্চিত হতে কিছুটা সময় নিবে তবে আপনি এর মধ্যেও কাজ করতে পারবেন))

অন্য সম্ভাবনা যে সূচী পৃষ্ঠাগুলির একটি বড় অংশ মৃত সারি দ্বারা দখল করা হয়েছে, যা শূন্যস্থান দ্বারা সরানো যেতে পারে। আপনি সেটিংটি দিয়ে টেবিলটি তৈরি করেছেন autovacuum_enabled=true- তবে আপনি কি কখনও অটোভ্যাকিউমিং শুরু করেছেন? নাকি VACUUMম্যানুয়ালি চালাবেন ?

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