Εισαγωγή
Αν έχετε κοιτάξει ποτέ ορισμούς πεδίων σε ένα module του Odoo, πιθανόν να έχετε δει index=True σε κάποιο πεδίο — μικρό, σχεδόν ασήμαντο στην όψη, αλλά με μεγάλο αντίκτυπο όταν τα δεδομένα μεγαλώσουν. Αυτό το ένα flag μπορεί να αλλάξει εντυπωσιακά την ταχύτητα αναζητήσεων και φιλτραρισμάτων σε βάσεις με χιλιάδες ή εκατομμύρια εγγραφές.
Αυτό το άρθρο εξηγεί με απλό τρόπο τι σημαίνει να είναι «indexed» ένα πεδίο στο μοντέλο δεδομένων του Odoo, τι κάνει στη βάση δεδομένων και πότε αξίζει να το χρησιμοποιήσετε σε προσαρμογές ή αναθεωρήσεις modules. Η γνώση αυτή βοηθάει να παίρνετε σωστές αποφάσεις κατά την ανάπτυξη ή τη συντήρηση ενός συστήματος Odoo.
Τι σημαίνει «indexed» πεδίο στο Odoo
Στο ORM του Odoo, ένα πεδίο χαρακτηρίζεται ως indexed όταν στον ορισμό του υπάρχει index=True. Αυτό δίνει εντολή στο PostgreSQL να δημιουργήσει ένα πίνακα ευρετηρίου (B-tree από προεπιλογή) στη στήλη της βάσης που αντιστοιχεί στο πεδίο, κατά την εγκατάσταση ή την αναβάθμιση του module.
Για να γίνει πιο κατανοητό, αρκεί να φανταστείτε ένα απλό παράδειγμα ορισμού πεδίου σε Python — χωρίς να χρειάζεται να αντιγράψουμε τον κώδικα εδώ.
class SaleOrder(models.Model):
_name = 'sale.order'
reference = fields.Char(string='Reference', index=True)
state = fields.Selection([...], index=True)
partner_id = fields.Many2one('res.partner', index=True)
Στην διεπαφή χρήστη δεν υπάρχει κάποια ένδειξη ότι ένα πεδίο είναι indexed — δεν εμφανίζεται κουμπί ή ετικέτα. Η διαφορά είναι αθέατη και βρίσκεται αποκλειστικά στην βάση δεδομένων και στον τρόπο που εκτελούνται τα ερωτήματα.
Ουσιαστικά το indexed πεδίο επηρεάζει την ταχύτητα. Με ευρετήριο, η PostgreSQL εντοπίζει ταιριαστές εγγραφές πολύ πιο γρήγορα, ειδικά σε μεγάλους πίνακες. Χωρίς ευρετήριο, ο engine πρέπει να ψάξει κάθε γραμμή (sequential scan). Με ευρετήριο, πλοηγείται σε μια ταξινομημένη δομή και βρίσκει τα αποτελέσματα απευθείας.
Ποιες τύποι πεδίων στο Odoo υποστηρίζουν το index=True
Τα περισσότερα πρωτογενή (scalar) πεδία στο ORM δέχονται το index attribute:
- Πεδία Char και Text
- Πεδία Integer και Float
- Πεδία Date και Datetime
- Πεδία Selection
- Πεδία Many2one (συχνά indexάρονται)
- Πεδία Boolean
Σχέσεις όπως One2many και Many2many δεν αντιστοιχούν απευθείας σε μία μόνο στήλη για indexing, επομένως το index δεν εφαρμόζεται σε αυτές. Επιπλέον, υπολογιζόμενα πεδία που δεν αποθηκεύονται στη βάση (non-stored) δεν μπορούν να ευρετηριαστούν αφού δεν έχουν στήλη.
Πώς λειτουργεί το πεδίο στο υπόβαθρο της βάσης
Κατά την αρχικοποίηση ή την αναβάθμιση ενός module, το Odoo συγκρίνει τον ορισμό των πεδίων με το σχήμα της βάσης. Για κάθε πεδίο που έχει index=True, εκτελείται το αντίστοιχο SQL ώστε να δημιουργηθεί το ευρετήριο στην PostgreSQL.
Η προεπιλογή είναι ο B-tree τύπος ευρετηρίων, ιδανικός για συγκρίσεις ισότητας (=), ερωτήματα εύρους (>, <, BETWEEN) και ταξινομήσεις — δηλαδή τις πιο συνηθισμένες λειτουργίες φιλτραρίσματος και ταξινόμησης στο Odoo.
Πώς αλληλεπιδρά με το ORM του Odoo
Το ORM μεταφράζει τα Python domain σε SQL. Για παράδειγμα, ένα domain [('state', '=', 'sale')] γίνεται WHERE state = 'sale'. Αν το πεδίο state έχει ευρετήριο, η PostgreSQL το αξιοποιεί και αποφεύγει το πλήρες σκανάρισμα του πίνακα.
Τα Many2one πεδία αποτελούν ένα πολύ κοινό σενάριο. Το partner_id σε μια πώληση αποθηκεύει το ακέραιο id του πελάτη. Όταν φιλτράρετε τις παραγγελίες για συγκεκριμένο πελάτη, το ερώτημα είναι WHERE partner_id = X — και με ευρετήριο το lookup παραμένει γρήγορο ακόμα και σε εκατοντάδες χιλιάδες παραγγελίες.
Indexes και επιπτώσεις στις εγγραφές (writes)
Τα ευρετήρια έχουν κόστος: κάθε εισαγωγή, ενημέρωση ή διαγραφή απαιτεί και ενημέρωση των ευρετηρίων. Σε πίνακες με πολλά indexes, οι εγγραφές γίνονται λίγο πιο αργές. Συνήθως το trade-off είναι αποδεκτό, αλλά δεν έχει νόημα να indexάρετε τα πάντα χωρίς σκέψη.
Η επιλογή index='trigram'
Από το Odoo 16 και μετά, η ιδιότητα index δέχεται και την τιμή 'trigram'. Αυτό δημιουργεί GIN trigram ευρετήριο μέσω του extension pg_trgm, ιδανικό για γρήγορο pattern matching σε ILIKE αναζητήσεις — χρήσιμο σε ονόματα προϊόντων ή πελατών όπου οι χρήστες πληκτρολογούν μερικά γράμματα.
name = fields.Char(string='Product Name', index='trigram')
Είναι πιο ειδική επιλογή που χρησιμοποιείται σε πεδία που συχνά αναζητούνται με μερική αντιστοίχιση στο standard του Odoo.
Πρακτικές επιχειρησιακές χρήσεις
Παρακάτω ακολουθούν πρακτικά παραδείγματα όπου το indexed πεδίο κάνει εμφαντική διαφορά στην καθημερινή λειτουργία.
1. CRM: Φιλτράρισμα ευκαιριών κατά υπεύθυνο πωλήσεων
Οι υπεύθυνοι πωλήσεων φιλτράρουν συχνά το pipeline ανά χρήστη. Το user_id στο crm.lead είναι ευρετηριασμένο σε τυπικές εγκαταστάσεις Odoo, γι' αυτό το φιλτράρισμα παραμένει γρήγορο ακόμα και με χιλιάδες leads. Το ίδιο ισχύει αν προσθέσετε custom Many2one προς χρήστη ή ομάδα — indexάρετέ το εάν θα το φιλτράρετε συχνά.
2. Πωλήσεις: Αναζητήσεις παραγγελιών με βάση την κατάσταση
Το πεδίο state στο sale.order είναι συχνά indexαρισμένο, επιτρέποντας γρήγορο άνοιγμα λιστών όπως «επιβεβαιωμένες» ή «αναμονή παράδοσης». Επιλογές (selection) που αποτελούν κοινά φίλτρα αξίζουν index.
3. Αποθήκη: Εντοπισμός κινήσεων ανά προϊόν
Οι κινήσεις αποθέματος μεγαλώνουν γρήγορα σε επιχειρήσεις διανομής ή παραγωγής. Ένα ευρετήριο στο product_id του stock.move επιτρέπει γρήγορη αναζήτηση όλων των κινήσεων για συγκεκριμένο προϊόν — κρίσιμο για αναφορές ιχνηλασιμότητας σε πολυσύχναστα αποθέματα.
4. Λογιστήριο: Φιλτράρισμα εγγραφών ημερολογίου ανά πελάτη/προμηθευτή
Οι λογιστές ανοίγουν συχνά βιβλία για συγκεκριμένο πελάτη ή προμηθευτή. Το partner_id σε account.move.line είναι ευρετηριασμένο ώστε οι αναζητήσεις αυτές να παραμένουν γρήγορες ακόμη και με χρόνια οικονομικών κινήσεων.
5. Custom modules: Πεδία αναφοράς για ιχνηλασιμότητα
Σε custom λύσεις, συνηθίζεται να προσθέτετε πεδία αναφοράς (π.χ. εξωτερικός κωδικός έργου). Αν τα πεδία αυτά θα χρησιμοποιούνται συχνά σε φίλτρα ή αναζητήσεις, το index=True διατηρεί επιδόσεις καθώς τα δεδομένα μεγαλώνουν.
Πώς να δημιουργήσετε ή να τροποποιήσετε ένα indexed πεδίο
Στην Python (ανάπτυξη custom module)
Η προσθήκη index=True σε έναν ορισμό πεδίου σε Python είναι απλή: προσθέστε το ως keyword argument όταν δηλώνετε το πεδίο.
from odoo import models, fields
class ProjectTask(models.Model):
_inherit = 'project.task'
x_external_ref = fields.Char(
string='External Reference',
index=True,
help='Reference number from the external system'
)
Μετά την αλλαγή, αναβαθμίστε το module με odoo-bin -u your_module_name ή μέσω του backend. Το Odoo θα εντοπίσει το νέο πεδίο και θα δημιουργήσει το αντίστοιχο ευρετήριο στη βάση.
Μπορείτε επίσης να προσθέσετε ευρετήριο σε υπάρχον πεδίο με override, αλλά αυτό απαιτεί προσοχή ώστε να μην αλλάξετε αρνητικά τη συμπεριφορά του πεδίου.
Στο Odoo Studio
Το Studio επιτρέπει τη δημιουργία πεδίων χωρίς κώδικα, αλλά δεν προσφέρει επιλογή για να ενεργοποιήσετε το indexing από το UI. Τα πεδία που φτιάχνονται με Studio δεν έχουν index=True από προεπιλογή.
Αν χρειάζεστε ευρετήριο σε πεδίο που δημιουργήθηκε με Studio για λόγους επιδόσεων, η συγκροτημένη λύση είναι να μετατρέψετε την προσαρμογή σε σωστό Python module και να προσθέσετε το index=True — μια εργασία για προγραμματιστή Odoo.
Προσθήκη ευρετηρίου απευθείας στην PostgreSQL
Σε ορισμένες περιπτώσεις, όπως όταν κάνετε βελτιστοποίηση σε παραγωγική βάση χωρίς αναβάθμιση module, ο DBA μπορεί να δημιουργήσει ευρετήριο χειροκίνητα με SQL.
CREATE INDEX CONCURRENTLY idx_sale_order_partner_id
ON sale_order (partner_id);
Η χρήση CONCURRENTLY αποφεύγει το κλείδωμα του πίνακα κατά τη δημιουργία του ευρετηρίου — σημαντικό σε παραγωγικά συστήματα. Παρόλ' αυτά, χρειάζεται συντονισμός με την αναπαράσταση του module ώστε ο κώδικας και η βάση να παραμένουν συγχρονισμένα.
Βέλτιστες πρακτικές
Indexάρετε πεδία που χρησιμοποιούνται μέσα σε domain queries
Αν ένα πεδίο χρησιμοποιείται συχνά σε domains — σε φίλτρα λίστας, αυτοματισμούς, cron jobs ή ως εξάρτηση σε υπολογισμένα πεδία — τότε είναι καλός υποψήφιος για ευρετήριο. Τα πιο συνηθισμένα παραδείγματα είναι Many2one, state και πεδία αναφοράς/κωδικού.
Ακολουθήστε τις επιλογές του ίδιου του Odoo
Καλό μέτρο είναι να δείτε τις standard υλοποιήσεις του Odoo (π.χ. sale.order, account.move, stock.move) και να αντιγράψετε τις επιλογές indexing που έχουν κάνει οι core developers — αυτές βασίζονται σε εμπειρία και πραγματική χρήση σε παραγωγικά περιβάλλοντα.
Πάντα indexάρετε Many2one σε μοντέλα με μεγάλο όγκο
Σε μοντέλα που συσσωρεύουν πολλές εγγραφές (π.χ. εγγραφές ημερολογίου, κινήσεις αποθέματος, γραμμές παραγγελιών), indexάρετε τα Many2one που χρησιμοποιούνται για φιλτράρισμα. Το κόστος στο write είναι συνήθως μικρό μπροστά στη βελτίωση στο read.
Σκεφτείτε trigram για πεδία κειμένου
Σε Odoo 16+, αν οι χρήστες αναζητούν συχνά μερική αντιστοιχία σε πεδία Char (π.χ. όνομα προϊόντος, όνομα πελάτη), εξετάστε το index='trigram' αντί του B-tree — ιδανικό για ILIKE αναζητήσεις.
Επαληθεύστε ότι τα ευρετήρια χρησιμοποιούνται πραγματικά
Μετά την προσθήκη ευρετηρίου, τρέξτε EXPLAIN ANALYZE στο ερώτημα για να δείτε αν ο planner το χρησιμοποιεί. Αν συνεχίζει να επιλέγει sequential scan, ίσως ο πίνακας είναι μικρός ή οι συνθήκες του query δεν ταιριάζουν με τον τύπο ευρετηρίου.
Τεκμηριώστε τις αποφάσεις για indexing
Στους custom modules αφήστε ένα σύντομο σχόλιο γιατί ένα πεδίο indexάρεται — βοηθάει μελλοντικούς developers να καταλάβουν την πρόθεση και να μην αφαιρέσουν το ευρετήριο κατά λάθος σε refactors.
Συνηθισμένα λάθη και παγίδες
Το λάθος του "indexάρω τα πάντα"
Ένα κλασικό λάθος είναι να βάλει κάποιος index=True σε κάθε πεδίο από φόβο. Αυτό είναι αντιπαραγωγικό: κάθε ευρετήριο καταναλώνει χώρο και επιβραδύνει τις εγγραφές. Σε πίνακες με υψηλό όγκο writes, τα περιττά indexes μπορούν να κάνουν το σύστημα πιο αργό.
Index σε μικρούς πίνακες: άχρηστη πολυπλοκότητα
Σε πίνακες με λίγες εκατοντάδες εγγραφές, ο planner συχνά προτιμά sequential scan από το ευρετήριο. Τα ευρετήρια αρχίζουν να δείχνουν όφελος όταν οι πίνακες μεγαλώσουν σε χιλιάδες εγγραφές. Το να indexάρετε σπάνια χρησιμοποιούμενα lookup tables δεν προσφέρει πρακτικό όφελος.
Ξεχνάτε να αναβαθμίσετε το module μετά την προσθήκη index=True
Απλά να προσθέσετε index=True στον Python ορισμό δεν φτιάχνει αυτόματα το ευρετήριο στη βάση — πρέπει να κάνετε upgrade του module (-u module_name) ή αναβάθμιση από το backend. Η παράλειψη αυτής της ενέργειας προκαλεί συχνή σύγχυση.
Δεν περιμένετε ότι ένα B-tree θα επιταχύνει πάντα ILIKE
Ένα κανονικό B-tree δεν βοηθά σε ILIKE '%λέξη%' όπου υπάρχει wildcard στην αρχή. Σε αυτές τις περιπτώσεις χρειάζεται index='trigram' ή λύσεις full-text search για γρήγορη μερική αναζήτηση.
Μη λησμονείτε τα αποθηκευμένα υπολογιζόμενα πεδία
Τα αποθηκευμένα (stored) υπολογιζόμενα πεδία έχουν στήλη στη βάση και μπορούν να indexαριστούν. Συχνά χάνεται αυτή η ευκαιρία: αν ένα stored computed πεδίο χρησιμοποιείται σε domains, το να το indexάρετε μπορεί να βελτιώσει σημαντικά τις επιδόσεις.
Συμπέρασμα
Η ιδιότητα index=True μπορεί να μοιάζει μικρή, αλλά έχει μεγάλο ρόλο στην απόδοση όσο αυξάνει ο όγκος δεδομένων. Όταν χρησιμοποιηθεί σωστά, διατηρεί αναζητήσεις και αναφορές γρήγορες· όταν χρησιμοποιηθεί επιπόλαια, προσθέτει κόστος χωρίς όφελος.
Το συμπέρασμα είναι ξεκάθαρο: indexάρετε πεδία που χρησιμοποιούνται συχνά σε domain φίλτρα, ιδιαίτερα Many2one σε μοντέλα με μεγάλο όγκο. Ακολουθήστε τις επιλογές των standard modules του Odoo, αποφύγετε την υπερβολική ευρετηρίαση σε μικρούς πίνακες και, αν είστε σε Odoo 16+, σκεφτείτε index='trigram' για γρήγορη μερική αναζήτηση κειμένου.
Είναι πιο εύκολο να σχεδιαστεί σωστά η στρατηγική ευρετηρίασης εξαρχής παρά να κυνηγάτε αργές ερωτήσεις σε παραγωγή αργότερα.
Αναπτύσσετε ένα έργο με Odoo;
Στην Dasolo, υποστηρίζουμε επιχειρήσεις στην υλοποίηση, προσαρμογή και βελτιστοποίηση Odoo. Αναλαμβάνουμε ανάπτυξη custom modules, βελτίωση επιδόσεων σε υπάρχον σύστημα ή σχεδιασμό νέου έργου, με πρακτική τεχνική εμπειρία.
Αν αντιμετωπίζετε αργά ερωτήματα, πολύπλοκες προσαρμογές ή χρειάζεστε συμβουλευτική για βέλτιστες πρακτικές ανάπτυξης Odoo, μπορούμε να σας βοηθήσουμε. Επικοινωνήστε με την ομάδα της Dasolo και πείτε μας πάνω σε τι δουλεύετε.