Η παλαιότερη και πιο συνηθισμένη ερώτηση που γίνεται είναι αυτή που αφορά το query performance. Για αυτή την ερώτηση έχουν γραφτεί εκατομμύρια γραμμές σε άρθρα και έχουν γίνει χιλιάδες παρουσιάσεις.
Συγκεκριμένη απάντηση δεν θα βρει κανείς πουθενά και είναι απόλυτα λογικό καθώς η κάθε περίπτωση είναι διαφορετική και χρειάζεται διαφορετική λύση.
Αυτό που μπορώ με σιγουριά να πω είναι ότι για να δώσει κάποιος λύση στο εκάστοτε πρόβλημα θα πρέπει να έχει γνώση των εσωτερικών δομών και αρχιτεκτονική του SQL Server πάνω από καλώς.
Δείτε μια περίπτωση που μου έτυχε χθες.
Έχω μια database αρκετά συμπαθητική σε μέγεθος και η οποία είναι ζωτικής σημασίας. Σε αυτή υπάρχουν δύο κυρίαρχοι πίνακες ο Τ1 με πάνω από 100Μ rows και ο Τ2 με μερικές χιλιάδες.
Σε αυτούς τους πίνακες υπάρχουν indexes και φυσικά υπάρχει και primary key.
Υπάρχει ένα view που μαζεύει δεδομένα από αυτούς τους δύο και το οποίο είναι το παρακάτω
CREATE VIEW [dbo].V1
AS
SELECT T1.*
FROM dbo.T1
LEFT OUTER JOIN dbo.T2 ON dbo.T1.Code = dbo.T2.Code
WHERE (dbo.T1.Status = 0) AND (dbo.T1.Display = 1)
GO
Και γίνεται κλήση στο συγκεκριμένο view κάθε 5 sec καθώς πρέπει να γεμίζει ένα monitor tool.
Και το execution plan για αυτό είναι το παρακάτω
Επίσης αυτό έχει το παρακάτω IO cost
Όπως φαίνεται για να επιστρέψει 5 rows διαβάζει το σύμπαν και επειδή είναι μεγάλος ο αριθμός των εγγραφών το query παραλληλίζει για να επιστρέψει όσο το δυνατόν γρήγορα τα δεδομένα.
Δεν με απασχολεί ιδιαίτερα ο παραλληλισμός καθώς είναι κάτι που γίνεται αλλά αυτό που δημιούργησε το παραλληλισμό και δεν είναι άλλο από τoν αριθμό των logical reads που είναι τεράστιος.
Σε ένα quiz που έκανα για να δω τις απαντήσεις με συναδέλφους όλοι πρότειναν να δημιουργηθεί index composite στα πεδία που χρησιμοποιούνται στο where του view δηλαδή ο παρακάτω
CREATE NONCLUSTERED INDEX [IDX_T1_Status_Display] ON [dbo].[T1]
(
[Status] ASC,
[Display] ASC
)
Το αποτέλεσμα όμως της εκτέλεσης είναι το εξής
Όπως φαίνεται δεν γίνεται χρήση του index και ο λόγος είναι απλός οι τιμές που έχουν αυτά τα πεδία είναι είτε 0 είτε ένα 1, άρα το selectivity και το density του index είναι τέτοιο που οδηγεί τον optimizer να κάνει table scan μόνο που στην περίπτωση μας ο πίνακας έχει clustered index και έτσι κάνει clustered index scan.
Θα μπορούσα να σταματήσω εδώ το άρθρο αυτό και να σας το θέσω σαν quiz αλλά δεν θα το κάνω :)
Η απάντηση ήταν και ξεκάθαρη από την αρχή στο μυαλό μου και είναι δημιουργία filtered index με βάση το πώς ζητάει τις εγγραφές το view. Ναι θα φτιάξω ένα index για ένα και μόνο query που τυγχάνει όμως να είναι το κυρίαρχο για την εφαρμογή και την βάση, και δεν είναι τσαπατσούλικη λύση καθώς όποιος πιστεύει ότι πρέπει να έχει μόνο γενικού σκοπού indexes λυπάμαι αλλά έχει λάθος.
Έτσι λοιπόν ο index έγινε filtered όπως παρακάτω
CREATE NONCLUSTERED INDEX [IDX_T1_Status_Display] ON [dbo].[T1]
(
[Status] ASC,
[Display] ASC
)
WHERE ([status]=(0) AND [display]=(1))
Και το αποτέλεσμα της εκτέλεσης έγινε όπως παρακάτω
Όπως εμφανώς είναι αναγνώσιμο τα logical reads έχουν δραματικά μειωθεί και είναι εύκολο για τον καθένα πλέον να φανταστεί το πόσο έχει βελτιωθεί το query αλλά και η απόκριση της εφαρμογής.
άμα είσαι Clay Regazzoni...
/*antonch*/