de Martin LE TARNEC.

Columnas combinadas


Esta sección trata de una confusión muy común que afecta a los índices concatenados .

El primer ejemplo es nuevamente acerca de los tipos de fechas y tiempo pero al revés. La siguiente sentencia MySQL combina un dato y una columna de tiempo para aplicar un rango filtrado sobre ambas columnas.

SELECT ...
  FROM ...
 WHERE ADDTIME(date_column, time_column)
     > DATE_ADD(now(), INTERVAL -1 DAY)

La sentencia selecciona todos los registros de las últimas 24 horas. Y no puede usar el índice concatenado (DATE_COLUMN, TIME_COLUMN) correctamente porque la búsqueda no está realizada sobre las columnas indexadas sino sobre datos derivados.

Es posible evitar este problema usando un tipo de datos, que contenga ambos: una fecha y un componente de tiempo (p.ej., MySQL DATETIME). Después se puede usar esta columna sin llamar una función:

SELECT ...
  FROM ...
 WHERE datetime_column
     > DATE_ADD(now(), INTERVAL -1 DAY)

Desafortunadamente, en general no es posible cambiar la tabla cuando nos enfrentamos a este problema.

La siguiente opción es un índice basado en una función si la base de datos lo soporta (aunque tienen muchas desventajas como vimos antes). Cuando se usa MySQL, de todos modos los índices basados en funciones no son una opción.

Es todavía posible escribir una sentencia con la que la base de datos pueda usar un índice concatenado sobre DATE_COLUMN,TIME_COLUMN con un acceso de predicado, por lo menos parcialmente. Para ello, se agrega una condición adicional sobre DATE_COLUMN.

 WHERE ADDTIME(date_column, time_column)
     > DATE_ADD(now(), INTERVAL -1 DAY)
   AND date_column
    >= DATE(DATE_ADD(now(), INTERVAL -1 DAY))

La nueva condición es absolutamente redundante pero es un filtro directo sobre DATE_COLUMN que puede usarse como acceso de predicado. Aunque esta técnica no es perfecta, es generalmente un buen método y suficiente .

Sugerencia

Usa una condición redundante sobre las columnas significantes cuando una condición de rango combina varias columnas.

Para PostgreSQL, es preferible usar la sintaxis con valores de registro.

Se puede también usar esa técnica cuando se almacenan datos y tiempo en columnas de texto, pero se tienen que emplear formatos de fecha y de tiempo que producen un orden cronológico cuando son ordenados de manera lexicográfica, por ejemplo, como sugiere el estándar ISO 8601 (YYYY-MM-DD HH:MM:SS). El siguiente ejemplo utiliza la función Oracle TO_CHAR para este propósito:

SELECT ...
  FROM ...
 WHERE date_string || time_string
     > TO_CHAR(sysdate - 1, 'YYYY-MM-DD HH24:MI:SS')
   AND date_string
    >= TO_CHAR(sysdate - 1, 'YYYY-MM-DD')

Vamos a enfrentarnos al problema aplicando una condición de rango sobre varias columnas nuevamente en la sección titulada Paginar a través del resultado. Se empleará también el mismo método de aproximación para atenuarlo.

A veces, tenemos el caso inverso y es posible que se desee usarlo para complicar intencionadamente una condición, pero no se podrá utilizar de ninguna manera como predicado de acceso. Ya se ha visto este problema al hablar de los efectos de las variables Bind sobre condiciones LIKE. Considera el siguiente ejemplo:

SELECT last_name, first_name, employee_id
  FROM employees
 WHERE subsidiary_id = ?
   AND last_name LIKE ?

Asumiendo que existe un índice sobre SUBSIDIARY_ID y uno más sobre LAST_NAME, ¿qué es lo más adecuado para esta sentencia?

Sin saber la posición del comodín en el criterio de la búsqueda, es imposible dar una respuesta cualificada. El optimizador no tiene otra elección que "suponer". Si se sabe que siempre existe un comodín que encabeza la búsqueda, se puede complicar intencionadamente la condición LIKE para que el optimizador no pueda considerar el índice sobre LAST_NAME.

SELECT last_name, first_name, employee_id
  FROM employees
 WHERE subsidiary_id = ?
   AND last_name || '' LIKE ?

Basta con agregar una cadena de caracteres vacía sobre la columna LAST_NAME. Sin embargo, se trata de una opción de último recurso. Escógela solo si es absolutamente necesario.

Si te gusta mi manera de explicar, te encantará mi libro.

Acerca del autor

Foto de Markus Winand

Markus Winand enseña eficientemente SQL, en casa y online. Minimiza el tiempo de desarrollo utilizando moderno SQL y optimiza el tiempo de ejecución con indexación inteligente. Para ello también ha publicado el libro SQL Performance Explained.

“Use The Index, Luke” de Markus Winand se halla bajo licencia Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License.
Aspectos legales | Contacto | SIN GARANTÍA | Marcas | Privacy | CC-BY-NC-ND 3.0 licencia