একটি বড় IN এর সাথে একটি পোস্টগ্রিজ ক্যোয়ারী অনুকূল করা


30

এই ক্যোয়ারীটি আপনি অনুসরণ করেন এমন লোকদের দ্বারা তৈরি পোস্টগুলির একটি তালিকা পেয়েছে। আপনি সীমাহীন সংখ্যক লোককে অনুসরণ করতে পারেন তবে বেশিরভাগ লোক <1000 অন্যান্যকে অনুসরণ করে।

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

EXPLAIN ANALYZE SELECT
    "Post"."id",
    "Post"."actionId",
    "Post"."commentCount",
    ...
FROM
    "Posts" AS "Post"
INNER JOIN "Users" AS "user" ON "Post"."userId" = "user"."id"
LEFT OUTER JOIN "ActivityLogs" AS "activityLog" ON "Post"."activityLogId" = "activityLog"."id"
LEFT OUTER JOIN "WeightLogs" AS "weightLog" ON "Post"."weightLogId" = "weightLog"."id"
LEFT OUTER JOIN "Workouts" AS "workout" ON "Post"."workoutId" = "workout"."id"
LEFT OUTER JOIN "WorkoutLogs" AS "workoutLog" ON "Post"."workoutLogId" = "workoutLog"."id"
LEFT OUTER JOIN "Workouts" AS "workoutLog.workout" ON "workoutLog"."workoutId" = "workoutLog.workout"."id"
WHERE
"Post"."userId" IN (
    201486,
    1825186,
    998608,
    340844,
    271909,
    308218,
    341986,
    216893,
    1917226,
    ...  -- many more
)
AND "Post"."private" IS NULL
ORDER BY
    "Post"."createdAt" DESC
LIMIT 10;

উৎপাদনের:

Limit  (cost=3.01..4555.20 rows=10 width=2601) (actual time=7923.011..7973.138 rows=10 loops=1)
  ->  Nested Loop Left Join  (cost=3.01..9019264.02 rows=19813 width=2601) (actual time=7923.010..7973.133 rows=10 loops=1)
        ->  Nested Loop Left Join  (cost=2.58..8935617.96 rows=19813 width=2376) (actual time=7922.995..7973.063 rows=10 loops=1)
              ->  Nested Loop Left Join  (cost=2.15..8821537.89 rows=19813 width=2315) (actual time=7922.984..7961.868 rows=10 loops=1)
                    ->  Nested Loop Left Join  (cost=1.71..8700662.11 rows=19813 width=2090) (actual time=7922.981..7961.846 rows=10 loops=1)
                          ->  Nested Loop Left Join  (cost=1.29..8610743.68 rows=19813 width=2021) (actual time=7922.977..7961.816 rows=10 loops=1)
                                ->  Nested Loop  (cost=0.86..8498351.81 rows=19813 width=1964) (actual time=7922.972..7960.723 rows=10 loops=1)
                                      ->  Index Scan using posts_createdat_public_index on "Posts" "Post"  (cost=0.43..8366309.39 rows=20327 width=261) (actual time=7922.869..7960.509 rows=10 loops=1)
                                            Filter: ("userId" = ANY ('{201486,1825186,998608,340844,271909,308218,341986,216893,1917226, ... many more ...}'::integer[]))
                                            Rows Removed by Filter: 218360
                                      ->  Index Scan using "Users_pkey" on "Users" "user"  (cost=0.43..6.49 rows=1 width=1703) (actual time=0.005..0.006 rows=1 loops=10)
                                            Index Cond: (id = "Post"."userId")
                                ->  Index Scan using "ActivityLogs_pkey" on "ActivityLogs" "activityLog"  (cost=0.43..5.66 rows=1 width=57) (actual time=0.107..0.107 rows=0 loops=10)
                                      Index Cond: ("Post"."activityLogId" = id)
                          ->  Index Scan using "WeightLogs_pkey" on "WeightLogs" "weightLog"  (cost=0.42..4.53 rows=1 width=69) (actual time=0.001..0.001 rows=0 loops=10)
                                Index Cond: ("Post"."weightLogId" = id)
                    ->  Index Scan using "Workouts_pkey" on "Workouts" workout  (cost=0.43..6.09 rows=1 width=225) (actual time=0.001..0.001 rows=0 loops=10)
                          Index Cond: ("Post"."workoutId" = id)
              ->  Index Scan using "WorkoutLogs_pkey" on "WorkoutLogs" "workoutLog"  (cost=0.43..5.75 rows=1 width=61) (actual time=1.118..1.118 rows=0 loops=10)
                    Index Cond: ("Post"."workoutLogId" = id)
        ->  Index Scan using "Workouts_pkey" on "Workouts" "workoutLog.workout"  (cost=0.43..4.21 rows=1 width=225) (actual time=0.004..0.004 rows=0 loops=10)
              Index Cond: ("workoutLog"."workoutId" = id)
Total runtime: 7974.524 ms

কীভাবে আপাতত এইটি অনুকূলিত করা যায়?

আমার কাছে নিম্নলিখিত সূচকগুলি রয়েছে:

-- Gets used
CREATE INDEX  "posts_createdat_public_index" ON "public"."Posts" USING btree("createdAt" DESC) WHERE "private" IS null;
-- Don't get used
CREATE INDEX  "posts_userid_fk_index" ON "public"."Posts" USING btree("userId");
CREATE INDEX  "posts_following_index" ON "public"."Posts" USING btree("userId", "createdAt" DESC) WHERE "private" IS null;

সম্ভবত এটির জন্য একটি বৃহত আংশিক যৌগিক সূচক প্রয়োজন createdAtএবং userIdকোথায় private IS NULL?

উত্তর:


29

বিশাল-তালিকা ব্যবহারের পরিবর্তে IN, একটি VALUESঅভিব্যক্তিতে যোগ দিন, বা তালিকাটি যথেষ্ট বড় হলে একটি টেম্প টেবিল ব্যবহার করুন, এটি সূচী করুন, তারপরে এতে যোগদান করুন।

পোস্টগ্র্রেএসকিউএল অভ্যন্তরীণভাবে এবং স্বয়ংক্রিয়ভাবে এটি করতে পারত তবে ভাল লাগবে তবে এই পরিকল্পনাকারী কীভাবে তা জানেন না।

অনুরূপ বিষয়:


28

INপোস্টগ্রিসে নির্মাণের দুটি ভিন্ন রূপ রয়েছে var একটি সাব-কোয়েরি এক্সপ্রেশন (একটি সেট ফেরত ) নিয়ে কাজ করে, অন্যটি মানগুলির তালিকা সহ , যা কেবল সংক্ষিপ্ত

expression = value1
OR
expression = value2
OR
...

আপনি দ্বিতীয় ফর্মটি ব্যবহার করছেন, যা একটি সংক্ষিপ্ত তালিকার জন্য সূক্ষ্ম তবে দীর্ঘ তালিকার জন্য খুব ধীর। পরিবর্তে সাবকোরি এক্সপ্রেশন হিসাবে আপনার মানগুলির তালিকা সরবরাহ করুন। আমাকে সম্প্রতি এই রূপটি সম্পর্কে সচেতন করা হয়েছিল :

WHERE "Post"."userId" IN (VALUES (201486), (1825186), (998608), ... )

আমি একটি অ্যারে পাস করতে পছন্দ করি, অযৌক্তিক এবং এতে যোগ দিতে পারি। অনুরূপ কর্মক্ষমতা, তবে বাক্য গঠনটি আরও ছোট:

...
FROM   unnest('{201486,1825186,998608, ...}'::int[]) "userId"
JOIN   "Posts" "Post" USING ("userId")

প্রদত্ত সেট / অ্যারেতে কোনও সদৃশ না হওয়া পর্যন্ত সমান । JOINরিটার্নের সদৃশ সারি সহ দ্বিতীয় ফর্ম , অন্যদিকে প্রথমটিIN একক উদাহরণ দেয় returns এই সূক্ষ্ম পার্থক্য এছাড়াও বিভিন্ন ক্যোয়ারী পরিকল্পনা, কারণ।

স্পষ্টতই, আপনার একটি সূচক প্রয়োজন "Posts"."userId"
জন্য খুব দীর্ঘ তালিকা (হাজার), একটি সূচীবদ্ধ টেম্প টেবিল সঙ্গে যেতে @Craig মত সুপারিশ করেছে। এটি উভয় টেবিলের উপর সম্মিলিত বিটম্যাপ সূচক স্ক্যান করতে দেয়, যা ডিস্ক থেকে আনার জন্য ডেটা পৃষ্ঠায় একাধিক টিপল থাকে তাড়াতাড়ি দ্রুত হয়।

সম্পর্কিত:

একদিকে: আপনার নামকরণের কনভেনশন খুব সহায়ক নয়, আপনার কোডটি ভার্বোজ এবং পড়তে শক্ত করে তোলে। বরং আইনী, লোয়ার-কেস, অব্যর্থ সনাক্তকারী সনাক্ত করুন।

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