Corriger les conversions implicites
Le problème des conversions implicites
Les conversions implicites se produisent lorsque SQL Server doit convertir un type de données en un autre pour effectuer une opération.
Par exemple, si vous comparez une colonne de type VARCHAR avec une valeur de type NVARCHAR, SQL Server devra convertir la valeur de la colonne en NVARCHAR avant de pouvoir effectuer la comparaison.
Cela peut entraîner un scan complet de la table au lieu d’une recherche rapide dans l’index.
Voici un exemple de requête qui pose problème :
DECLARE @Nom NVARCHAR(50) = 'Feragotto';
SELECT *
FROM Contact.Contact
WHERE Nom = @Nom
Si Nom est de type VARCHAR dans la base de données, mais que le paramètre @Nom est de type NVARCHAR (ce qui est le cas par défaut avec ADO.NET), SQL Server devra convertir la colonne Nom en NVARCHAR avant de pouvoir effectuer la comparaison.
Cela peut empêcher l’utilisation de l’index sur la colonne Nom, et empêcher une estimation correcte du nombre de lignes retournées (l’estimation de cardinalité).
Pourquoi les conversions implicites peuvent convertir la colonne plutôt que le paramètre
Lorsque SQL Server doit comparer deux valeurs de types de données différents, il peut convertir implicitement l’une des valeurs pour que les types soient compatibles.
La règle générale est que SQL Server choisit le type de données avec la priorité la plus élevée pour la conversion.
Cela signifie que si une colonne est de type VARCHAR et qu’un paramètre est de type NVARCHAR, SQL Server va convertir la colonne en NVARCHAR plutôt que de convertir le paramètre en VARCHAR.
Ces règles de prorité sont communes à tous les langages de programmation qui permettent des conversions implicites dans les comparaisons, pour plusieurs raisons :
-
Minimiser la perte de données : Convertir une valeur de type
VARCHARenNVARCHARest moins susceptible de causer une perte de données que l’inverse. Par exemple, si vous convertissez une valeurNVARCHARenVARCHAR, vous pourriez perdre des caractères si la valeurNVARCHARcontient des caractères qui ne peuvent pas être représentés enVARCHAR. -
Cohérence et prévisibilité : En suivant une hiérarchie de priorité claire, SQL Server peut s’assurer que les conversions de types de données sont effectuées de manière cohérente et prévisible.
ADO.NET et NVARCHAR
ADO.NET utilise NVARCHAR comme type de données par défaut pour les paramètres de requêtes préparées. Cela peut poser problème si les colonnes de la base de données sont de type VARCHAR. En effet, SQL Server devra convertir les données de la colonne en NVARCHAR avant de pouvoir effectuer la comparaison, ce qui peut entraîner des problèmes de performance.
Par exemple, si vous avez une table avec une colonne Nom de type VARCHAR et que vous utilisez ADO.NET pour exécuter une requête avec un paramètre de type NVARCHAR, SQL Server devra convertir la colonne Nom en NVARCHAR avant de pouvoir effectuer la comparaison.
Identifier les conversions implicites
Pour identifier les conversions implicites dans vos requêtes, vous pouvez utiliser les plans d’exécution de SQL Server. Les plans d’exécution montrent comment SQL Server exécute une requête et peuvent inclure des informations sur les conversions implicites.

Dans les cas les plus évidents, vous verrez une icône d’avertissement jaune à côté de l’opération qui indique qu’une conversion implicite a eu lieu. En survolant cette icône, vous pouvez voir des détails sur la conversion implicite, y compris les types de données impliqués.
L’avertissement peut indiquer deux problèmes : un problème de performance dû à l’impossibilité d’utiliser un index (index seek), et un problème d’estimation de cardinalité (cardinality estimation). Il arrive que le problème d’estimation de cardinalité soit bénin (conversion implicute dans la partie SELECT), mais l’avertissement de seek est en lien avec une conversion implicute dans un prédicat, et c’est un signe qu’il faut optimiser la requête.
Corriger les conversions implicites
Pour corriger les conversions implicites, vous devez modifier les types de données dans vos requêtes pour qu’ils correspondent aux types de données dans la base de données. Par exemple, si la colonne Nom est de type VARCHAR, vous pouvez modifier votre requête pour utiliser un paramètre de type VARCHAR au lieu de NVARCHAR.
Voici un exemple de correction :
// Avant : utilisation de NVARCHAR par défaut
command.Parameters.AddWithValue("@Nom", Nom);
// Après : utilisation explicite de VARCHAR
command.Parameters.Add("@Nom", SqlDbType.VarChar).Value = Nom;
Entity Framework et conversions implicites
Par défaut, Entity Framework peut utiliser des types de données qui ne correspondent pas exactement aux types de données dans la base de données. Par exemple, si vous avez une colonne de type VARCHAR dans votre base de données, Entity Framework pourrait utiliser un type de données .NET qui est mappé à NVARCHAR dans SQL Server. Cela peut entraîner des conversions implicites lorsque les requêtes sont exécutées.
Dans des versions antérieures d’Entity Framework, les chaînes de caractères étaient mappées par défaut à NVARCHAR. Cependant, dans Entity Framework Core, vous pouvez spécifier le type de données à utiliser pour chaque propriété dans votre modèle.
Voici un exemple de comment spécifier le type de données pour une propriété dans Entity Framework :
public class Contact
{
public int Id { get; set; }
[Column(TypeName = "varchar(50)")]
public string Nom { get; set; }
}
Dans cet exemple, la propriété Nom est mappée à une colonne de type VARCHAR(50) dans la base de données. Cela peut aider à éviter les conversions implicites lorsque des requêtes sont exécutées.
Vous pouvez également configurer les types de données dans la classe de configuration de l’entité. Par exemple, si vous utilisez Fluent API pour configurer votre modèle, vous pouvez spécifier le type de données comme suit :
modelBuilder.Entity<Contact>()
.Property(c => c.Nom)
.HasColumnType("varchar(50)");
Cela permet de s’assurer que la colonne Nom est mappée à un type VARCHAR dans la base de données, ce qui peut aider à éviter les conversions implicites.
Voici un exemple complet de configuration d’une entité avec Fluent API pour éviter les conversions implicites :
public class ContactConfiguration : EntityTypeConfiguration<Contact>
{
public ContactConfiguration()
{
Property(c => c.Nom)
.HasColumnType("varchar(50)")
.IsRequired();
}
}
Dans cet exemple, la propriété Nom est configurée pour être mappée à une colonne de type VARCHAR(50) dans la base de données.
[Besoin de services avec SQL Server ? Contactez-moi]