2017-10-04 13 views
5

Je tombe sur un article décrivant une situation différente dans laquelle le code SQL est probablement incorrect. Cependant, il y en a un point qui me surprend. Ils prétendentLes conditions sont-elles sans puanteur ISNULL?

il est sage de gérer explicitement les valeurs NULL dans les colonnes nullable, en utilisant COALESCE pour fournir une valeur par défaut

ISNULL est mentionné aussi. Ils font également référence à ce MSDN web page en donnant un exemple avec ISNULL. L'idée de base est ici qu'il est préférable d'utiliser

SELECT COUNT(*) FROM [dbo].[Table1] WHERE ISNULL([c2],0) > 2; 

puis

SELECT COUNT(*) FROM [dbo].[Table1] WHERE [c2] > 2; 

Cependant, la première variante ne sera pas SARG, alors que le résultat ne soit pas influencée par ISNULL du tout. Je comprends la nécessité de gérer NULL en utilisant ISNULL ou COALESCE dans la sortie, cependant, j'essaie toujours d'utiliser IS NULL ou IS NOT NULL pour gérer NULL dans le prédicat. Est-ce que je manque quelque chose? Quel est le point de la question MSDN?

EDIT: afin de réagir à la discussion et surtout sur ce post j'ai préparé un test simple

IF OBJECT_ID('dbo.LogTable', 'U') IS NOT NULL DROP TABLE dbo.LogTable 

SELECT TOP 100000 DATEADD(day, (ABS(CHECKSUM(NEWID())) % 65530), 0) datesent , 
     CASE WHEN (ABS(CHECKSUM(NEWID())) % 100) = 1 THEN NULL ELSE (ABS(CHECKSUM(NEWID())) % 1000) END ivalue 
INTO [LogTable] 
FROM sys.sysobjects 
CROSS JOIN sys.all_columns 

CREATE INDEX ix_logtable_ivalue ON LogTable(ivalue asc) INCLUDE(datesent); 

-- Q1 
select * from logtable where isnull(ivalue, 0) > 998 

-- Q2 
select * from logtable where ivalue > 998 

Cependant, le ivalue au 1 er trimestre n'est pas Sarg. Y a-t-il des captures? Comment devrais-je créer l'attribut SARG pour cette donnée et requête particulière?

+4

Vous avez raison. Ne mettez pas de vérifications inutiles 'NULL', car cela peut empêcher l'utilisation d'index. Je recommande fortement 'IS NULL' /' IS NOT NULL'. Ce sont les constructions standard ANSI. –

+9

Le fait que cet exemple provienne de quelque chose qui prétend détecter un mauvais code de base de données pour l'améliorer est très inquiétant. Vous avez * besoin * de penser à ce qui pourrait arriver lorsque vous comparez des valeurs qui peuvent être 'NULL ', mais mettre' ISNULL' par réflexe partout est carrément faux. –

+0

'Quel est le point de la question MSDN'? Dunno :-) La remarque de la [source d'origine] (https://www.red-gate.com/simple-talk/sql/t-sql-programming/sql-code-smells/#not-handling-null- values-in-nullable-columns) a du sens en calculant des choses, mais l'exemple donné de [MSDN] (https://msdn.microsoft.com/en-us/library/dd172133 (v = vs.100) .aspx) est complètement erroné. –

Répondre

6

La vérification isnull dans l'exemple fourni est inutile. null > 2 renvoie null, qui n'est pas "true", et donc ces lignes seront quand même exclues de la requête. Pour démarrer, utiliser isnull de cette manière empêchera l'optimiseur d'utiliser l'index sur c2 si vous en avez un. En bref - cela ressemble à un mauvais conseil.

+1

"null> 2 renvoie null" - Non, cette comparaison renvoie inconnue. Un peu pédant mais les nulls sont déroutants. Le point est toujours correct - il n'y a aucune raison de vérifier null. – SMor

+1

@SMor: très pédant, car le type de données booléen n'existe que virtuellement en T-SQL. S'il existait en réalité (je le souhaite, ce serait très utile), il est presque certain que le résultat 'UNKNOWN' serait représenté par' NULL'. Je ne suis pas sûr de savoir comment 'NULL' serait" plus confus "que" UNKNOWN ", cependant, puisque c'est ce que la chose est là pour en premier lieu. –

+0

'utiliser isnull de cette façon empêchera l'optimiseur d'utiliser l'index sur c2 si vous en avez un' n'est pas tout à fait raison car il peut encore être publié un 'index scan', comme [Pankaj Manek nous montre brillamment ici] (http://www.sqlservercentral.com/blogs/sqlyse-with-pankaj-manek/2015/08/20/isnull-around-the-predicate-and-sargability/). L'affirmation est vraie pour 'index seek'. –