go backsqlschool blogs list

Another Example Why you must avoid Implicit Conversions in T-SQL

by Antonios Chatzipavlis

Εισαγωγή

Αν και δεν είμαι αρκετά σίγουρος ότι όλοι έχουν καταλάβει ότι θα πρέπει να αποφεύγουν όπως ο διάολος το λιβάνι τα implicit conversions εντούτοις αυτό είναι κάτι γνωστό και πηγή δεινών αν αυτό γίνεται στην T-SQL. Υπάρχουν αρκετά άρθρα που το αναφέρουν αυτό και με αυτό το post θα συμπληρώσω και εγώ ακόμα ένα παράδειγμα με σκοπό μήπως και κάποιοι συνετιστούν και σταματήσουν να το κάνουν.

Αυτό το post αποφάσισα να το γράψω μετά από ένα πραγματικό γεγονός που έγινε σε πραγματικό περιβάλλον εργασίας και το οποίο δημιουργούσε αρκετά προβλήματα.
Για να γίνει κατανοητό αυτό ας έρθουμε να δούμε ένα παράδειγμα και για αυτό το λόγο ας έρθουμε να φτιάξουμε μια βάση με ένα πίνακα που θα παίξει το ρόλο του πειραματόζωου και θα είναι ένας πίνακας πελατών όπου η απόφαση που έχουμε είναι να υπάρχει το ΑΦΜ σαν σημείο αναφοράς για το record άρα και primary key. Σε αυτόν θα βάλουμε 10.000 rows. Όλα αυτά μπορούν να γίνουν με τα παρακάτω script

Το Παράδειγμα

CREATE DATABASE LocalTest;
GO
USE LOCALTEST;
GO
CREATE TABLE Customers
(
    AFM CHAR(9) NOT NULL ,
    CustomerName VARCHAR(250) NOT NULL,
    ContactName VARCHAR(50) NOT NULL
);
GO
ALTER TABLE Customers
ADD CONSTRAINT PK_Customers PRIMARY KEY (AFM);
GO

SET NOCOUNT ON;
DECLARE @I INT=100000000;
WHILE @I < 100010000
BEGIN
    INSERT INTO Customers 
    VALUES 
    (
        CAST(@I AS VARCHAR(9)),
        'Customer :'+ CONVERT(VARCHAR,@I),
        'Contact :'+ CONVERT(VARCHAR,@I)
    );
    SET @I+=1;
END;
GO
SELECT    COUNT(*) 
FROM    Customers;
GO
SELECT    AFM,
        CustomerName,
        ContactName
FROM    Customers;
GO

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

Έχω δύο developers ο ένας γράφει αυτό ως εξής

SELECT    AFM,
        CustomerName,
        ContactName
FROM    Customers
WHERE AFM='100000010';
GO

Και ο άλλος όπως παρακάτω

SELECT    AFM,
        CustomerName,
        ContactName
FROM    Customers
WHERE AFM=100000010;

Και οι δύο παίρνουν το ίδιο αποτέλεσμα. Αν όμως δω τα execution plans θα διαπιστώσω ότι το ένα έκανε seek που είναι και το λογικό και αυτό ήθελα να γίνει ενώ στο δεύτερο έκανε scan!!!!!. Ωραίο ε;
Ας δούμε όμως και το κόστος τους; Το  πρώτο έχει 4% και το δεύτερο 96%!!!

image

Η Επεξήγηση


 

Τι όμως έκανε το δεύτερο να έχει άλλη συμπεριφορά στην εκτέλεση με συνέπεια να έχω και  μεγαλύτερο κόστος;
Αν στα εxecution plans έρθουμε στο δεύτερο query περάσουμε το mouse στο Clustered Index Scan θα δούμε εμφανίζεται ένα tooltip όπως στην παρακάτω εικόνα

image

Αυτό μπορούμε να το δούμε και επιλέγοντας το node στο execution plan πατήσουμε F4 και μας εμφανιστεί το Properies window

image

 

Και στις δύο εικόνες θα παρατηρήσουμε ότι στο Pedicate λέει ξεκάθαρα ότι έκανε CONVERT_IMPLICIT(int,[LocalTest].[dbo].[Customers].[AFM],0)=[@1], κάτι το οποίο στο πρώτο δεν γίνεται.

Επίλογος

Όλα αυτά έγιναν διότι ο δεύτερος developer αποφάσισε σκεπτόμενος ότι το ΑΦΜ είναι νούμερο και μπορεί να το γράψει όπως το έγγραψε και ο SQL Server το δέχεται καθώς κάνει implicit conversions. Αναρωτιέμαι αν θα το έκανε κάτι τέτοιο αν έγγραφε σε C# και μη μου πείτε ότι εκεί δεν σου επιτρέπει να κάνεις κάτι τέτοιο, στο επιτρέπει αλλά δεν το κάνεις γιατί σου έχει περάσει με ένεση μέσα στο αίμα σου ότι κάτι τέτοιο είναι κακό.

Ημερομηνία: 29 May 2012 14:44
Αξιολόγηση:
Κατηγορίες:
Tags:
Share it:

Σχετικά Blog Post

Αφήστε το σχόλιο σας - 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