go backsqlschool blogs list

Get All tables row count without using Count(*) function

by Antonios Chatzipavlis

Η δύναμη της συνήθειας είναι το μεγαλύτερο ναρκωτικό του μυαλού και δεν το αφήνει να σκεφτεί αποδοτικά. Αλήθεια πόσες φορές κάνουμε μηχανικά κάποια πράγματα επειδή τα έχουμε συνηθίσει στα τόσα χρόνια που κάνουμε αυτή την δουλειά ;

Καθημερινά ασχολούμαι με πάνω από 3500 databases και μου είναι αδύνατον να θυμάμαι όλες τις λεπτομέρειες που η κάθε μία έχει. Μεγάλος αριθμός από αυτές περιέχουν μεγάλο αριθμό από tables και rows. Συχνά κυρίως για λόγους συντήρησης χρειάζεται να ξέρω τον αριθμό των rows που όλοι ή κάποιο table έχει ώστε το script μου να γνωρίζει αυτόν.

Η δύναμη της συνήθειας για να μάθω κάτι τέτοιο είναι απλά να  γράφω ένα SELECT COUNT(*) FROM <TABLE_NAME>.
Έχω γράψει στο παρελθόν άρθρο (How a SELECT COUNT(*) query executed) για το πώς εκτελείται η COUNT(*) και δεν έχω να προσθέσω κάτι σε αυτό καθώς κάνει σωστά αυτό που πρέπει να κάνει.

Παρόλα αυτά όμως υπάρχουν περιπτώσεις που έχω πίνακες που έχουν μεγάλο αριθμό rows (> 50.000.000) και με μεγάλο record length που ακόμα και έτσι το να πάρω αποτέλεσμα από την COUNT(*) χρειάζεται πάνω από 5 sec και αυτό με κάνει να περιμένω και δεν έχω πάντα την πολυτέλεια για αυτό.  

Μια τέτοια περίπτωση είχα την εβδομάδα που μας πέρασε και πάνω στην πίεση το μυαλό γύρισε mode και δεν σκέφτηκε την πεπατημένη αλλά σκέφτηκε πραγματικά και πρακτικά την αρχιτεκτονική του SQL Server.

Έτσι αντί να κάνω ένα για παράδειγμα ένα SELECT COUNT(*) FROM Customers θυμήθηκα ότι το πλήθος των εγγραφών υπάρχει σαν πεδίο στο sys.partitions DMV και έτσι με το παρακάτω query πήρα την πληροφορία που ήθελα δηλαδή των αριθμό των εγγραφών ΑΜΕΣΑ!.
SELECT object_name(object_id) as objectname,SUM(rows) as rowscount
FROM sys.partitions
WHERE index_id IN(0,1)
AND object_id=object_id('dbo.Customers')
GROUP BY object_name(object_id)
objectname    rowscount
------------  -----------
Customers      91

Get rows from all database tables

Από εκεί και μετά λέω γιατί δεν φτιάχνω και ένα query που να μου γυρνάει άμεσα για κάθε πίνακα τα πλήθος των rows και το αποτέλεσμα είναι το παρακάτω
select    schema_name(o.schema_id) as [schema_name]
    ,    o.name as [table_name]
    ,    sum(p.rows) as [rows_count] 
from    sys.partitions as p
inner join    sys.objects as o on p.object_id=o.object_id
where    o.type='U'
        and 
        p.index_id IN(0,1)
group by    schema_name(o.schema_id) 
        ,    o.name
order by    [schema_name],[table_name];
schema_name   table_name                 rows_count
------------  -------------------------- -------------
dbo           Categories                 8
dbo           CustomerCustomerDemo       0
dbo           CustomerDemographics       0
dbo           Customers                  91
dbo           Employees                  9
dbo           EmployeeTerritories        49
dbo           Order Details              2155
dbo           Orders                     830
dbo           Products                   77
dbo           Region                     4
dbo           Shippers                   3
dbo           Suppliers                  29
dbo           Territories                53
Σημείωση Θα πρέπει όμως να τονίσω ότι αν θέλουμε να πάρουμε από τις εφαρμογές μας το πλήθος των rows θα πρέπει να χρησιμοποιηθεί η παραδοσιακή μέθοδος καθώς επιστρέφει πάντα σωστά αποτελέσματα καθώς η σύμφωνα με τα BOL η rows column γυρνάει approximate value κυρίως γιατί μπορεί να τρέχουν uncommitted batches.
Από την άλλη όμως δεν έχω share locks και δεν αναγκάζομαι να χρησιμοποιήσω nolock query hint.

/*antonch*/
Ημερομηνία: 25 October 2015 23:01
Share it:

Αφήστε το σχόλιο σας - Leave your comment

Τα σχόλια έχουν κλείσει.
Επιτρέπονται μόνο τα σχόλια από τα μέλη του SqlSchool.gr.


newsletter subscription

Εάν επιθυμείτε να λαμβάνετε ενημέρωση από εμάς, δώστε μας το e-mail σας.
PASS chapter logo
Official Professional Association for SQL Server (PASS) chapter for Greece
Join to PASS