PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Πολλοί που ήδη χρησιμοποιούν εξηγήστε.tensor.ru - Η υπηρεσία οπτικοποίησης σχεδίου PostgreSQL μπορεί να μην γνωρίζει μια από τις υπερδυνάμεις της - να μετατρέψει ένα δυσανάγνωστο κομμάτι του αρχείου καταγραφής διακομιστή ...

PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα
… σε ένα όμορφα σχεδιασμένο ερώτημα με συμφραζόμενες συμβουλές για τους σχετικούς κόμβους σχεδίου:

PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα
Σε αυτή τη μεταγραφή του δεύτερου μέρους του έκθεση στο PGConf.Russia 2020 Θα σας πω πώς τα καταφέραμε.

Η μεταγραφή του πρώτου μέρους, αφιερωμένη σε τυπικά προβλήματα απόδοσης ερωτημάτων και τις λύσεις τους, μπορείτε να βρείτε στο άρθρο "Συνταγές για άρρωστα ερωτήματα SQL".



Πρώτα, ας κάνουμε το χρωματισμό - και δεν θα χρωματίσουμε πλέον το σχέδιο, το έχουμε ήδη ζωγραφίσει, είναι ήδη όμορφο και κατανοητό, αλλά το αίτημα.

Μας φάνηκε ότι το αίτημα που βγήκε από το αρχείο καταγραφής με ένα μη μορφοποιημένο "φύλλο" φαίνεται πολύ άσχημο και επομένως άβολο.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Ειδικά όταν οι προγραμματιστές «κολλούν» το σώμα του αιτήματος στον κώδικα (αυτό, φυσικά, είναι αντι-μοτίβο, αλλά συμβαίνει) σε μία γραμμή. Φρίκη!

Ας το ζωγραφίσουμε κάπως πιο όμορφα.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Και αν μπορούμε να το σχεδιάσουμε όμορφα, δηλαδή να αποσυναρμολογήσουμε και να συναρμολογήσουμε το σώμα του αιτήματος πίσω, τότε μπορούμε να "επισυνάψουμε" μια υπόδειξη σε κάθε αντικείμενο αυτού του αιτήματος - τι συνέβη στο αντίστοιχο σημείο του σχεδίου.

Συντακτικό δέντρο ερωτήματος

Για να γίνει αυτό, το ερώτημα πρέπει πρώτα να αναλυθεί.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Διότι, έχουμε ο πυρήνας του συστήματος τρέχει στο NodeJS, τότε φτιάξαμε μια ενότητα για αυτό, μπορείτε βρείτε το στο github. Στην πραγματικότητα, πρόκειται για εκτεταμένες "δεσμεύσεις" στα εσωτερικά του ίδιου του αναλυτή PostgreSQL. Δηλαδή, η γραμματική είναι απλά δυαδική μεταγλώττιση και γίνονται δεσμεύσεις σε αυτήν από το NodeJS. Λάβαμε ως βάση τις ενότητες άλλων ανθρώπων - δεν υπάρχει κανένα μεγάλο μυστικό εδώ.

Τροφοδοτούμε το σώμα της αίτησης εισαγωγής στη συνάρτησή μας - στην έξοδο παίρνουμε ένα αναλυμένο δέντρο σύνταξης με τη μορφή ενός αντικειμένου JSON.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Τώρα μπορούμε να τρέξουμε μέσα από αυτό το δέντρο προς την αντίθετη κατεύθυνση και να συναρμολογήσουμε το αίτημα με τις εσοχές, το χρωματισμό, τη μορφοποίηση που θέλουμε. Όχι, αυτό δεν είναι διαμορφώσιμο, αλλά πιστεύαμε ότι θα ήταν βολικό.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Κόμβοι ερωτήματος και σχεδίου χαρτογράφησης

Ας δούμε τώρα πώς μπορούμε να συνδυάσουμε το σχέδιο που αναλύσαμε στο πρώτο βήμα και το ερώτημα που αναλύσαμε στο δεύτερο.

Ας πάρουμε ένα απλό παράδειγμα - έχουμε ένα αίτημα που σχηματίζει ένα CTE και το διαβάζει δύο φορές. Δημιουργεί ένα τέτοιο σχέδιο.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

ΣΤΕ

Αν το κοιτάξετε προσεκτικά, αυτό πριν από την 12η έκδοση (ή ξεκινώντας από αυτήν με τη λέξη-κλειδί MATERIALIZED) σχηματισμός Το CTE είναι ένα άνευ όρων εμπόδιο στον προγραμματιστή.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Και, αυτό σημαίνει, αν δούμε κάπου στο αίτημα τη δημιουργία CTE και κάπου στο σχέδιο τον κόμβο CTE, τότε αυτοί οι κόμβοι «παλεύουν» μοναδικά μεταξύ τους, μπορούμε αμέσως να τους συνδυάσουμε.

Εργασία "με αστερίσκο"Σημείωση: Τα CTE μπορούν να είναι ένθετα.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα
Υπάρχουν πολύ κακώς φωλιασμένες, και μάλιστα με το ίδιο όνομα. Για παράδειγμα, μπορείτε μέσα CTE A κάνει CTE X, και στο ίδιο επίπεδο εσωτερικά CTE B Κανω ξανά CTE X:

WITH A AS (
  WITH X AS (...)
  SELECT ...
)
, B AS (
  WITH X AS (...)
  SELECT ...
)
...

Κατά τη σύγκριση, πρέπει να το καταλάβετε αυτό. Είναι πολύ δύσκολο να το καταλάβουμε αυτό με «μάτια» - ακόμη και βλέποντας το σχέδιο, ακόμη και βλέποντας το σώμα του αιτήματος. Εάν η γενιά CTE σας είναι πολύπλοκη, ένθετη, τα αιτήματα είναι μεγάλα, τότε είναι εντελώς αναίσθητη.

ΕΝΩΣΗ

Αν έχουμε λέξη-κλειδί στο αίτημα UNION [ALL] (ο χειριστής της ένωσης δύο δειγμάτων), τότε αντιστοιχεί στο σχέδιο σε έναν από τους δύο κόμβους Append, ή μερικά Recursive Union.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Αυτό που είναι "πάνω" UNION - αυτό είναι το πρώτο παιδί του κόμβου μας, που είναι "από κάτω" - το δεύτερο. Αν μέσω UNION έχουμε "κολλήσει" πολλά μπλοκ ταυτόχρονα, λοιπόν Append-ο κόμβος θα έχει ακόμα μόνο ένα, αλλά δεν θα έχει δύο παιδιά, αλλά πολλά - με τη σειρά που πηγαίνουν, αντίστοιχα:

  (...) -- #1
UNION ALL
  (...) -- #2
UNION ALL
  (...) -- #3

Append
  -> ... #1
  -> ... #2
  -> ... #3

Εργασία "με αστερίσκο": μέσα σε αναδρομική παραγωγή ανάκτησης (WITH RECURSIVE) μπορεί επίσης να είναι περισσότερα από ένα UNION. Αλλά μόνο το τελευταίο μπλοκ μετά το τελευταίο είναι πάντα αναδρομικό UNION. Όλα τα παραπάνω είναι ένα αλλά διαφορετικά UNION:

WITH RECURSIVE T AS(
  (...) -- #1
UNION ALL
  (...) -- #2, тут кончается генерация стартового состояния рекурсии
UNION ALL
  (...) -- #3, только этот блок рекурсивный и может содержать обращение к T
)
...

Τέτοια παραδείγματα πρέπει επίσης να μπορούν να «επικολληθούν». Σε αυτό το παράδειγμα, βλέπουμε ότι UNION-Τα τμήματα στο αίτημά μας ήταν 3 τεμάχια. Αντίστοιχα, ένα UNION αντιστοιχεί Append-κόμβος και ο άλλος - Recursive Union.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Δεδομένα ανάγνωσης-εγγραφής

Όλα, στρωμένα, τώρα ξέρουμε ποιο κομμάτι του αιτήματος αντιστοιχεί σε ποιο κομμάτι του σχεδίου. Και σε αυτά τα κομμάτια μπορούμε εύκολα και φυσικά να βρούμε εκείνα τα αντικείμενα που είναι «αναγνώσιμα».

Από την άποψη του ερωτήματος, δεν γνωρίζουμε αν πρόκειται για πίνακα ή για CTE, αλλά συμβολίζονται με τον ίδιο κόμβο RangeVar. Και στο "αναγνώσιμο" σχέδιο, αυτό είναι επίσης ένα αρκετά περιορισμένο σύνολο κόμβων:

  • Seq Scan on [tbl]
  • Bitmap Heap Scan on [tbl]
  • Index [Only] Scan [Backward] using [idx] on [tbl]
  • CTE Scan on [cte]
  • Insert/Update/Delete on [tbl]

Γνωρίζουμε τη δομή του σχεδίου και του αιτήματος, γνωρίζουμε την αντιστοιχία των μπλοκ, γνωρίζουμε τα ονόματα των αντικειμένων - κάνουμε μια σαφή σύγκριση.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Πάλι εργασία "με έναν αστερίσκο". Λαμβάνουμε ένα αίτημα, το εκτελούμε, δεν έχουμε ψευδώνυμα - απλώς το διαβάζουμε δύο φορές από ένα CTE.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Ας δούμε το σχέδιο - ποιο είναι το πρόβλημα; Γιατί είχαμε ψευδώνυμο; Δεν το παραγγείλαμε. Από πού παίρνει τέτοιο «νούμερο»;

Η PostgreSQL την προσθέτει η ίδια. Απλά πρέπει να το καταλάβεις ακριβώς ένα τέτοιο ψευδώνυμο για εμάς, για λόγους σύγκρισης με το σχέδιο, δεν έχει νόημα, απλά προστίθεται εδώ. Ας μην του δίνουμε σημασία.

Η δεύτερη εργασία "με έναν αστερίσκο": αν διαβάζουμε από έναν πίνακα διαμερισμάτων, τότε θα πάρουμε έναν κόμβο Append ή Merge Append, που θα αποτελείται από μεγάλο αριθμό «παιδιών», και καθένα από τα οποία θα είναι μερικά Scanαπό την ενότητα του πίνακα: Seq Scan, Bitmap Heap Scan ή Index Scan. Αλλά, σε κάθε περίπτωση, αυτά τα «παιδιά» δεν θα είναι σύνθετα ερωτήματα - έτσι μπορούν να διακριθούν αυτοί οι κόμβοι από Append στο UNION.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Καταλαβαίνουμε επίσης τέτοιους κόμπους, τους μαζεύουμε "σε ένα σωρό" και λέμε: "όλα όσα διαβάζετε από το megatable είναι ακριβώς εδώ και κάτω από το δέντρο".

«Απλοί» Κόμβοι Απόκτησης Δεδομένων

PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Values Scan σε σχέδιο αντιστοιχεί VALUES στο αίτημα.

Result είναι ένα αίτημα χωρίς FROM όπως SELECT 1. Ή όταν έχετε μια ψεύτικη έκφραση WHERE-block (τότε εμφανίζεται το χαρακτηριστικό One-Time Filter):

EXPLAIN ANALYZE
SELECT * FROM pg_class WHERE FALSE; -- или 0 = 1

Result  (cost=0.00..0.00 rows=0 width=230) (actual time=0.000..0.000 rows=0 loops=1)
  One-Time Filter: false

Function Scan "Mapyatsya" στο ομώνυμο SRF.

Αλλά με τα ένθετα ερωτήματα, όλα είναι πιο περίπλοκα - δυστυχώς, δεν μετατρέπονται πάντα σε InitPlan/SubPlan. Μερικές φορές μετατρέπονται σε ... Join ή ... Anti Join, ειδικά όταν γράφεις κάτι σαν WHERE NOT EXISTS .... Και δεν είναι πάντα δυνατός ο συνδυασμός εκεί - στο κείμενο του σχεδίου δεν υπάρχουν τελεστές που να αντιστοιχούν στους κόμβους του σχεδίου.

Πάλι εργασία "με έναν αστερίσκο": μερικοί VALUES στο αίτημα. Σε αυτή την περίπτωση και στο σχέδιο θα λάβετε αρκετούς κόμβους Values Scan.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Τα επιθήματα "αριθμός" θα βοηθήσουν στη διάκρισή τους μεταξύ τους - προστίθεται ακριβώς με τη σειρά με την οποία το αντίστοιχο VALUES-μπλοκάρει την πορεία του αιτήματος από πάνω προς τα κάτω.

Επεξεργασία δεδομένων

Φαίνεται ότι όλα στο αίτημά μας διευθετήθηκαν - μόνο Limit.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Αλλά όλα είναι απλά εδώ - τέτοιοι κόμβοι όπως Limit, Sort, Aggregate, WindowAgg, Unique «Χαρτογραφούν» ένας προς έναν στους αντίστοιχους χειριστές του αιτήματος, εάν βρίσκονται εκεί. Δεν υπάρχουν «αστέρια» και δεν υπάρχουν δυσκολίες.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Ενώνω

Δυσκολίες προκύπτουν όταν θέλουμε να συνδυάσουμε JOIN μεταξύ τους. Αυτό δεν είναι πάντα δυνατό, αλλά είναι δυνατό.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Από την άποψη του αναλυτή ερωτήματος, έχουμε έναν κόμβο JoinExpr, που έχει ακριβώς δύο παιδιά - αριστερά και δεξιά. Αυτό, αντίστοιχα, είναι αυτό που είναι "πάνω" το JOIN σας και αυτό που γράφεται "κάτω" στο ερώτημα.

Και από τη σκοπιά του σχεδίου, αυτοί είναι δύο απόγονοι κάποιων * Loop/* Join-κόμβος. Nested Loop, Hash Anti Join... είναι κάτι τέτοιο.

Ας χρησιμοποιήσουμε απλή λογική: αν έχουμε πίνακες Α και Β που «ενώνονται» μεταξύ τους στο σχέδιο, τότε στο ερώτημα θα μπορούσαν να βρίσκονται είτε A-JOIN-BΉ B-JOIN-A. Ας προσπαθήσουμε να συνδυάσουμε έτσι, προσπαθήστε να συνδυάσετε με τον αντίθετο τρόπο και ούτω καθεξής μέχρι να τελειώσουν τέτοια ζευγάρια.

Πάρε το συντακτικό μας, πάρε το σχέδιο μας, δες τους... δεν φαίνεται!
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Ας το ξανασχεδιάσουμε με τη μορφή γραφημάτων - ω, κάτι έχει ήδη γίνει παρόμοιο με κάτι!
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Ας παρατηρήσουμε ότι έχουμε κόμβους που έχουν ταυτόχρονα παιδιά Β και Γ - δεν μας έχει σημασία με ποια σειρά. Ας τα συνδυάσουμε και ας αναστρέψουμε την εικόνα του κόμβου.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Ας ξανακοιτάξουμε. Τώρα έχουμε κόμβους με παιδιά Α και ζεύγη (Β + Γ) - συμβατούς με αυτούς.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Εξαιρετική! Αποδεικνύεται ότι είμαστε αυτοί οι δύο JOIN από το ερώτημα με τους κόμβους του σχεδίου συνδυάστηκαν με επιτυχία.

Δυστυχώς, αυτό το πρόβλημα δεν λύνεται πάντα.
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Για παράδειγμα, εάν το αίτημα A JOIN B JOIN C, και στο σχέδιο, πρώτα απ 'όλα συνδέθηκαν οι "ακραίοι" κόμβοι A και C. Αλλά δεν υπάρχει τέτοιος τελεστής στο ερώτημα, δεν έχουμε τίποτα να επισημάνουμε, δεν υπάρχει τίποτα για να δεσμεύσουμε την υπόδειξη. Το ίδιο με το "κόμμα" όταν γράφεις A, B.

Αλλά, στις περισσότερες περιπτώσεις, σχεδόν όλοι οι κόμβοι καταφέρνουν να «λύσουν» και να αποκτήσουν έγκαιρα τέτοιο προφίλ στα αριστερά - κυριολεκτικά, όπως στο Google Chrome, όταν αναλύετε κώδικα JavaScript. Μπορείτε να δείτε πόσο καιρό κάθε γραμμή και κάθε πρόταση "εκτελείται".
PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Και για να σας διευκολύνουμε στη χρήση όλων αυτών, δημιουργήσαμε αποθήκευση αρχείο, όπου μπορείτε να αποθηκεύσετε και στη συνέχεια να βρείτε τα σχέδιά σας μαζί με συσχετισμένα ερωτήματα ή να μοιραστείτε έναν σύνδεσμο με κάποιον.

Εάν χρειάζεται απλώς να φέρετε ένα μη αναγνώσιμο αίτημα σε κατάλληλη μορφή, χρησιμοποιήστε το ο "κανονικοποιητής" μας.

PostgreSQL Query Profiler: Πώς να αντιστοιχίσετε σχέδιο και ερώτημα

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο