← Όλα τα άρθρα

Δεν φταίει η JavaScript που αργεί το site: κοιτάξτε τη βάση

Όλοι βελτιστοποιούν το frontend γιατί εκεί δείχνουν τα εργαλεία. Στο μεταξύ, το πραγματικό κόστος κρύβεται σε queries που κατεβάζουν ολόκληρα άρθρα για να εμφανίσουν μια λίστα τίτλων. Πού χάνουν στην πράξη την ταχύτητά τους τα server-rendered sites.

Δεν φταίει η JavaScript που αργεί το site: κοιτάξτε τη βάση

Με λίγα λόγια: Τα server-rendered sites χάνουν ταχύτητα και χρήματα στο επίπεδο δεδομένων, όχι στο frontend: queries λίστας που κατεβάζουν ολόκληρα άρθρα για να δείξουν τίτλους, σελίδες χωρίς cache που χτυπούν τη βάση σε κάθε επίσκεψη, και ίδια δεδομένα που ζητιούνται τρεις φορές ανά render. Επιλέξτε μόνο τα πεδία που εμφανίζετε, κάντε cache τη σελίδα, μοιράστε τα fetch, και κοιτάξτε το dashboard της βάσης· το Lighthouse δεν θα σας το δείξει ποτέ.

Οι συμβουλές απόδοσης στο διαδίκτυο είναι συντριπτικά συμβουλές frontend. Μέγεθος bundle, φορμά εικόνων, στρατηγικές hydration, φόρτωση γραμματοσειρών. Όλα αληθινά, όλα αξίζουν. Αλλά σε server-rendered sites, το μοτίβο που βρίσκω ξανά και ξανά όταν κάτι είναι πραγματικά αργό (ή πραγματικά ακριβό) είναι διαφορετικό: το επίπεδο δεδομένων κάνει πέντε φορές τη δουλειά που χρειάζεται η σελίδα, και κανείς δεν κοιτάει, γιατί το Lighthouse δεν μετράει τη βάση σας.

Η σελίδα λίστας που κατεβάζει βιβλιοθήκη

Η κλασική περίπτωση. Ένα ευρετήριο blog δείχνει είκοσι κάρτες: τίτλος, περίληψη, ημερομηνία, μικρογραφία. Το query από πίσω είναι ένα findMany() στον πίνακα των άρθρων χωρίς επιλογή πεδίων. Κάθε αίτημα τραβάει είκοσι ολόκληρα σώματα άρθρων, σε δύο γλώσσες αν το site είναι δίγλωσσο, συν κάθε στήλη JSON κρεμασμένη στο μοντέλο, για να εμφανίσει είκοσι τίτλους.

Στο localhost αυτό είναι αόρατο. Χιλιοστά του δευτερολέπτου. Στην παραγωγή εμφανίζεται σε τρία σημεία: χρόνος απόκρισης υπό φορτίο, egress βάσης στον λογαριασμό σας, και πίεση στις συνδέσεις όταν η κίνηση ανεβαίνει απότομα. Οι serverless πάροχοι Postgres χρεώνουν τα δεδομένα που μεταφέρονται προς τα έξω, και έχω δει ένα query λίστας να ευθύνεται για το μεγαλύτερο μέρος του egress ενός site χωρίς να συνεισφέρει τίποτα απ' όσα εμφάνιζε η σελίδα.

Η διόρθωση δεν έχει αίγλη: επιλέξτε τα πεδία που εμφανίζετε. Σε ένα ORM αυτό σημαίνει ρητό select. Καμιά φορά σημαίνει να κατεβείτε σε raw SQL για τα «καυτά» queries λίστας, γιατί το βολικό σχήμα του ORM είναι ακριβώς το ακριβό σχήμα. Ένα query που επιστρέφει τίτλους και περιλήψεις είναι σφάλμα στρογγυλοποίησης. Ένα query που επιστρέφει σώματα είναι ξεφόρτωμα εγγράφων.

Κάντε cache τη σελίδα, όχι το query

Μόλις τα queries γίνουν λιτά, το επόμενο ερώτημα είναι πόσο συχνά τρέχουν. Για sites περιεχομένου η ειλικρινής απάντηση είναι ότι οι περισσότερες σελίδες αλλάζουν σπάνια και δεν πειράζει οι αναγνώστες να δουν ελαφρώς παλιό περιεχόμενο. Γι' αυτό υπάρχει το incremental static regeneration (ή το απλό HTTP caching, ή ένα CDN με λογικό TTL): κάνεις render τη σελίδα, σερβίρεις το αποθηκευμένο αντίγραφο, το ανανεώνεις ανά διάστημα.

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

Δύο πράγματα δαγκώνουν εδώ. Πρώτον, οι caches στρώνονται σε επίπεδα και δεν ακυρώνονται όλες μαζί. Η cache δεδομένων του framework, το CDN και ο browser έχουν ο καθένας τη γνώμη του. Όταν αλλάζετε μεταβλητή περιβάλλοντος ή δείχνετε σε άλλη βάση, καθαρίστε τις σκόπιμα. Το να επιβιώνει η cache της πλατφόρμας από ένα redeploy είναι γνήσια μπερδευτική αποτυχία την πρώτη φορά που τη συναντάς. Δεύτερον, το ISR μετατοπίζει το πότε τρέχει ο κώδικας, κι αυτό αλλάζει το πώς μοιάζουν τα bugs. HTML που παράγεται στο build και HTML που παράγεται στην επανεπικύρωση μπορεί να διαφέρουν σε μικρές δομικές λεπτομέρειες, και οτιδήποτε πιο κάτω στη ροή συγκρίνει ή ταυτοποιεί τις σελίδες σας πρέπει να θεωρεί και τα δύο φυσιολογικά.

Φέρτε τα δεδομένα μία φορά, μοιράστε το αποτέλεσμα

Τα server components και τα partials κάνουν εύκολο το να ζητούν τρία μέρη μιας σελίδας ανεξάρτητα τα ίδια δεδομένα. Το header θέλει τις ρυθμίσεις του site, το footer επίσης, το σώμα της σελίδας το ίδιο: τρία queries εκεί που θα αρκούσε ένα. Κάντε deduplicate σε επίπεδο αιτήματος. Τα περισσότερα frameworks δίνουν φθηνό τρόπο να κάνετε memoize ένα fetch για τη διάρκεια ενός render. Χρησιμοποιήστε τον, και ανεβάστε τα κοινά δεδομένα στο layout.

Η συγγενική «μυρωδιά» είναι το fetch μέσα σε loop. Είκοσι κάρτες που πυροδοτούν από ένα δικό τους query είναι είκοσι διαδρομές προς μια βάση που θα απαντούσε με μία. Καταρράκτες που θα ήταν προφανείς σε ένα network tab κρύβονται εύκολα σε server κώδικα.

Μετρήστε το επίπεδο που κανείς δεν παρακολουθεί

Ο λόγος που η σπατάλη στη βάση επιβιώνει τόσο καιρό είναι ότι τίποτα δεν τη δείχνει. Η απόδοση frontend έχει ολόκληρη βιομηχανία εργαλείων. Για το επίπεδο δεδομένων πρέπει να κοιτάξετε μόνοι σας, και το κοίταγμα δεν είναι δύσκολο:

Καταγράψτε πλήθος queries ανά route στο development. Αν μια σελίδα τρέχει τριάντα queries, θα το μάθετε μόνο αν τα μετρήσετε. Δείτε στο dashboard του παρόχου βάσης τις γραμμές που διαβάστηκαν και τα δεδομένα που μεταφέρθηκαν, και αντιστοιχίστε τους μεγαλύτερους καταναλωτές πίσω σε routes. Και όταν ένας αριθμός φαίνεται λάθος, συνήθως είναι. Ο εμπειρικός μου κανόνας: μια σελίδα περιεχομένου πρέπει να κοστίζει περίπου όσο το μέγεθος του HTML της σε μεταφορά από τη βάση. Αν κοστίζει δεκαπλάσια, κάτι φέρνει σώματα για να εμφανίσει τίτλους.

Η δουλειά στο frontend κάνει ένα site να μοιάζει γρήγορο. Η δουλειά στο επίπεδο δεδομένων το κάνει φθηνό και το κρατάει γρήγορο όταν το επισκέπτεται όντως κόσμος. Κάντε και τα δύο, αλλά αν το site είναι server-rendered και κάτι δεν πάει καλά, κοιτάξτε πρώτα τα queries. Εκεί κρύβεται η σπατάλη, ακριβώς επειδή κανένα σκορ δεν πέφτει ποτέ όταν υπάρχει.

Τα βασικά σημεία