¿Es más rápido comprobar si length = 0 que compararlo con una cadena vacía?


He oído que en algunos lenguajes de programación es más rápido comprobar si la longitud de una cadena es 0, que comprobar si el contenido es "". ¿Es esto también cierto para T-SQL?

Muestra:

SELECT user_id FROM users WHERE LEN(user_email) = 0

Vs.

SELECT user_id FROM users WHERE user_email = ''
Author: Martin Smith, 2010-07-28

3 answers

Editar Has actualizado tu pregunta desde que la vi por primera vez. En ese ejemplo yo diría que definitivamente siempre debes usar

SELECT user_id FROM users WHERE user_email = ''

No

SELECT user_id FROM users WHERE LEN(user_email) = 0

El primero permitirá utilizar un índice. Como una optimización de rendimiento, esto superará a una micro optimización de cadenas cada vez. Para ver esto

SELECT * into #temp FROM [master].[dbo].[spt_values]

CREATE CLUSTERED INDEX ix ON #temp([name],[number])

SELECT [number] FROM #temp WHERE [name] = ''

SELECT [number] FROM #temp WHERE LEN([name]) = 0

Planes de ejecución

Planes de Ejecución

Respuesta original

En el siguiente código (SQL Server 2008-I "tomó prestado" el marco de tiempo de @8kb de la respuesta aquí) Obtuve una ligera ventaja para probar la longitud en lugar del contenido a continuación cuando @stringToTest contenía una cadena. Eran tiempos iguales cuando NULL. Probablemente no probé lo suficiente para sacar conclusiones firmes.

En un plan de ejecución típico, me imagino que la diferencia sería insignificante y si está haciendo tanta comparación de cadenas en TSQL, es probable que haga una diferencia significativa. probablemente esté usando un lenguaje diferente para ello.

DECLARE @date DATETIME2
DECLARE @testContents INT
DECLARE @testLength INT

SET @testContents = 0
SET @testLength = 0


DECLARE 
  @count INT,
  @value INT,
  @stringToTest varchar(100)


set @stringToTest = 'jasdsdjkfhjskdhdfkjshdfkjsdehdjfk'
SET @count = 1

WHILE @count < 10000000
BEGIN

  SET @date = GETDATE()
  SELECT @value = CASE WHEN @stringToTest = '' then 1 else 0 end
  SET @testContents = @testContents + DATEDIFF(MICROSECOND, @date, GETDATE())

  SET @date = GETDATE()
  SELECT @value = CASE WHEN len(@stringToTest) = 0 then 1 else 0 end
  SET @testLength = @testLength + DATEDIFF(MICROSECOND, @date, GETDATE())

  SET @count = @count + 1
END

SELECT 
  @testContents / 1000000. AS Seconds_TestingContents, 
  @testLength / 1000000. AS Seconds_TestingLength
 27
Author: Martin Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:07:08

Tendría cuidado de usar LEN en una cláusula WHERE ya que podría conducir a escaneos de tablas o índices.

También tenga en cuenta que si el campo es NULLcapaz de LEN(NULL) = NULL, por lo que tendría que definir el comportamiento, por ejemplo:

-- Cost .33
select * from [table]
where itemid = ''

-- Cost .53
select * from [table]
where len(itemid) = 0

-- `NULL`able source field (and assuming we treat NULL and '' as the same)
select * from [table]
where len(itemid) = 0 or itemid is NULL
 7
Author: StuartLC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-03 05:03:57

Acabo de probarlo en un escenario muy limitado y el plan de ejecución favorece ligeramente compararlo con una cadena vacía. (49% a 51%). Esto está trabajando con cosas en memoria, por lo que probablemente sería diferente si se compara con los datos de una tabla.

DECLARE @testString nvarchar(max)
SET @testString = ''

SELECT
    1
WHERE
    @testString = ''

SELECT
    1
WHERE
    LEN(@testString) = 0

Editar: Esto es con SQL Server 2005.

 5
Author: Evil Pigeon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-28 08:18:05