sql >> Base de Datos >  >> RDS >> Sqlserver

Servidor SQL ENTRE

Encontrar una forma de usar BETWEEN con la tabla tal como está funcionará, pero tendrá un peor rendimiento en todos los casos:

  • En el mejor de los casos, consumirá más CPU para hacer algún tipo de cálculo en las filas en lugar de trabajar con ellas como fechas.
  • En el peor de los casos, forzará una exploración de la tabla en cada fila de la tabla, pero si sus columnas tienen índices, entonces con la consulta correcta es posible realizar una búsqueda. Esto podría ser una GRAN diferencia de rendimiento, porque forzar las restricciones en una cláusula BETWEEN deshabilitará el uso del índice.

En su lugar, sugiero lo siguiente si tiene un índice en sus columnas de fecha y se preocupa por el rendimiento:

DECLARE
   @FromDate date = '20111101',
   @ToDate date = '20120201';

SELECT *
FROM dbo.YourTable T
WHERE
   (
      T.[Year] > Year(@FromDate)
      OR (    
         T.[Year] = Year(@FromDate)
         AND T.[Month] >= Month(@FromDate)
      )
   ) AND (
      T.[Year] < Year(@ToDate)
      OR (
         T.[Year] = Year(@ToDate)
         AND T.[Month] <= Month(@ToDate)
      )
   );

Sin embargo, es comprensible que no desee utilizar una construcción de este tipo, ya que es muy incómoda. Así que aquí hay una consulta de compromiso, que al menos usa computación numérica y usará menos CPU que la computación de conversión de fecha a cadena (aunque no lo suficiente como para compensar el escaneo forzado, que es el verdadero problema de rendimiento).

SELECT *
FROM dbo.YourTable T
WHERE
   T.[Year] * 100 + T.[Month] BETWEEN 201111 AND 201202;

Si tiene un índice en Year , puede obtener un gran impulso enviando la consulta de la siguiente manera, que tiene la oportunidad de buscar:

SELECT *
FROM dbo.YourTable T
WHERE
   T.[Year] * 100 + T.[Month] BETWEEN 201111 AND 201202
   AND T.[Year] BETWEEN 2011 AND 2012; -- allows use of an index on [Year]

Si bien esto rompe su requisito de usar un solo BETWEEN expresión, no es mucho más doloroso y funcionará muy bien con el Year índice.

También puedes cambiar de mesa. Francamente, usar números separados para las partes de la fecha en lugar de una sola columna con un tipo de datos de fecha no es bueno. La razón por la que no es bueno es por el problema exacto al que se enfrenta en este momento:es muy difícil de consultar.

En algunos escenarios de almacenamiento de datos donde el ahorro de bytes importa mucho, podría imaginar situaciones en las que podría almacenar la fecha como un número (como 201111 ) pero eso no es recomendable. Los mejores La solución es cambiar su tabla para usar fechas en lugar de dividir el valor numérico del mes y el año. Simplemente almacene el primer día del mes, reconociendo que representa el mes completo.

Si cambiar la forma en que usa estas columnas no es una opción pero aún puede cambiar su tabla, entonces puede agregar una columna calculada persistente:

ALTER Table dbo.YourTable
   ADD ActualDate AS (DateAdd(year, [Year] - 1900, DateAdd(month, [Month], '18991201')))
   PERSISTED;

Con esto solo puedes hacer:

SELECT *
FROM dbo.YourTable
WHERE
   ActualDate BETWEEN '20111101' AND '20120201';

El PERSISTED La palabra clave significa que, si bien obtendrá un escaneo, no tendrá que hacer ningún cálculo en cada fila, ya que la expresión se calcula en cada INSERCIÓN o ACTUALIZACIÓN y se almacena en la fila. Pero tú puedes obtenga una búsqueda si agrega un índice en esta columna, lo que hará que funcione muy bien (aunque en general, esto todavía no es tan ideal como cambiar para usar una columna de fecha real, porque ocupará más espacio y afectará INSERTAR y ACTUALIZACIONES):

CREATE NONCLUSTERED INDEX IX_YourTable_ActualDate ON dbo.YourTable (ActualDate);

Resumen:si realmente no puede cambiar la tabla de ninguna manera, entonces tendrá que hacer un compromiso de alguna manera. No será posible obtener la sintaxis simple que desea que también funcione bien, cuando sus fechas se almacenan divididas en columnas separadas.