2010-04-06 16 views
5

Tengo una tabla que almacena algunos datos básicos acerca de las sesiones de usuario en los sitios web de terceros. Esta es su estructura:MySQL para una mesa con varios índices que el índice de algunas de las mismas columnas

id, site_id, unixtime, unixtime_last, ip_address, uid 

Hay cuatro índices: id, site_id/unixtime, site_id/ip_address y site_id/uid

Hay muchos tipos diferentes de maneras que consultar esta tabla, y todos ellos son específicos de la Identificación del sitio. El índice con unixtime se usa para mostrar la lista de visitantes para una fecha o rango de tiempo determinado. Los otros dos se utilizan para encontrar todas las visitas desde una dirección IP o un "uid" (un valor de cookie único creado para cada visitante), así como para determinar si este es un visitante nuevo o un visitante que regresa.

Obviamente, almacenar site_id dentro de 3 índices no es eficiente tanto para la velocidad de escritura como para el almacenamiento, pero no veo forma de evitarlo, ya que necesito poder consultar rápidamente estos datos para un site_id específico.

¿Alguna idea sobre cómo hacer esto más eficiente?

yo no entiendo muy bien los árboles B, además de algunas cosas muy básicas, pero es más eficiente que la columna más a la izquierda de un índice sea el que tiene la menor varianza - ¿correcto? Porque consideré que site_id es la segunda columna del índice para ip_address y uid, pero creo que eso haría que el índice sea menos eficiente ya que el IP y el UID van a variar más de lo que lo haría el ID del sitio, porque solo tenemos alrededor de 8000 sitios únicos por servidor de base de datos, pero millones de visitantes únicos en todos los ~ 8000 sitios a diario.

También he considerado eliminar site_id de los índices IP y UID por completo, ya que las posibilidades de que el mismo visitante vaya a varios sitios que comparten el mismo servidor de base de datos son bastante pequeñas, pero en los casos donde esto sucede, me temo podría ser bastante lento determinar si este es un nuevo visitante a este site_id o no. La consulta sería algo así como:

select id from sessions where uid = 'value' and site_id = 123 limit 1 

... así que si este visitante había visitado este sitio antes, sería sólo es necesario encontrar una fila con este site_id antes de detenerse. Esto no sería necesariamente súper rápido, sino aceptablemente rápido. Pero digamos que tenemos un sitio que recibe 500,000 visitantes por día, y un visitante en particular ama este sitio y va allí 10 veces al día. Ahora llegan a otro sitio en el mismo servidor de base de datos por primera vez. La consulta anterior podría llevar bastante tiempo para buscar entre todos los miles de filas potencialmente para este UID, diseminadas por todo el disco, ya que no encontraría una para este ID de sitio.

Cualquier penetración en hacer esto lo más eficiente posible sería apreciado :)

actualización - esto es una tabla MyISAM con MySQL 5.0. Mis preocupaciones son tanto con el rendimiento como con el espacio de almacenamiento. Esta tabla es tanto lectura como escritura pesada. Si tuviera que elegir entre rendimiento y almacenamiento, mi principal preocupación es el rendimiento, pero ambos son importantes.

Utilizamos MemCached fuertemente en todas las áreas de nuestro servicio, pero eso no es una excusa para no preocuparse por el diseño de la base de datos. Quiero que la base de datos sea lo más eficiente posible.

+0

motor de almacenamiento? ¿versión de mysql? ¿Y cómo quiere que esto sea más eficiente, en cuanto al uso del disco o al rendimiento? ¿Y tienes problemas reales para resolver o es solo una pregunta retórica? – ggiroux

+0

mysql 5.0, motor myisam. Me preocupan tanto el espacio de almacenamiento como el rendimiento, ya que esta es una mesa pesada de lectura y escritura. Sí, problema real. :) – Sean

+0

¿Has leído Alto rendimiento MySQL? –

Respuesta

0

En primer lugar, si usa ip como una cadena, cámbiela a la columna INT UNSIGNED y use la función INET_ATON (expr) e INET_NTOA (expr) para tratar esto. La indexación en valores enteros es más eficiente que la indexación en cadenas de longitud variable.

+0

Todos los campos son, por supuesto, enteros ... – Sean

+0

Asegúrese de ser incompatible con IPv6. ¡Año 2000, aquí venimos! – derobert

0

Bien indexa el almacenamiento comercial para el rendimiento. Es difícil si quieres los dos. Es difícil optimizar esto más sin conocer todas las consultas que se ejecutan y sus cantidades por intervalo.

Lo que tenga funcionará. Si se encuentra con un cuello de botella, deberá averiguar si es la CPU, el ram, el disco y/o la red y ajustarse en consecuencia. Es difícil e incorrecto optimizar prematuramente.

Es probable que desee cambiar a innodb si tiene alguna actualización, de otro modo myisam es bueno para insertar/seleccionar. Además, dado que el tamaño de su fila es pequeño, puede buscar en el clúster mysql (nbd). También hay un motor de archivo que puede ayudar con los requisitos de almacenamiento, pero la partición en 5.1 es probablemente una mejor opción para analizar.

Voltear el orden de su índice no tiene ningún sentido, si estos índices ya se utilizan en todas sus consultas.

pero es más eficiente tener la columna más a la izquierda de un índice con la menor varianza, ¿correcto?

no estoy seguro pero no he escuchado esto antes. No me parece cierto para esta aplicación. La orden del índice es importante para la clasificación y al tener varios campos de índice exclusivos, permite que más consultas usen el índice.

4
Realmente no entiendo B-trees además de algunas cosas muy básicas, pero es más eficiente tener la columna más a la izquierda de un índice con la menor varianza, ¿correcto?

Hay una propiedad importante de los índices de árbol B que hay que tener en cuenta: Es posible (eficiencia) para buscar un prefijo arbitrario de la llave completa, pero no un sufijo . Si tiene un índice site_ip(site_id, ip) y solicita where ip = 1.2.3.4, MySQL no usará el índice site_ip. Si en su lugar tuviera ip_site(ip, site_id), entonces MySQL podría usar el índice ip_site.

Esta es una segunda propiedad de los índices de B-tree que también debes tener en cuenta: están ordenados. Un índice b-tree se puede usar para consultas como where site_id < 40.

También hay que tener en cuenta una propiedad importante de las unidades de disco: las lecturas secuenciales son baratas, las búsquedas no lo son. Si hay columnas usadas que no están en el índice, MySQL debe leer la fila de los datos de la tabla. Eso es generalmente una búsqueda, y lento. Entonces, si MySQL cree que terminará leyendo incluso un pequeño porcentaje de la tabla como este, ignorará el índice. Una exploración de tabla grande (una lectura secuencial) suele ser más rápida que las lecturas aleatorias de incluso un pequeño porcentaje de las filas de una tabla.

Lo mismo, por cierto, se aplica a las búsquedas a través de un índice. Encontrar una clave en un árbol B realmente requiere algunas búsquedas, por lo que encontrará que WHERE site_id > 800 AND ip = '1.2.3.4' no puede usar el índice site_ip, ya que cada site_id requiere varios índices para encontrar el inicio de los registros 1.2.3.4 para ese sitio. Sin embargo, se usaría el índice ip_site.

En última instancia, vas a tener que hacer un uso liberal de la evaluación comparativa y EXPLAIN para descubrir los mejores índices para tu base de datos. Recuerde, puede agregar y soltar libremente índices según sea necesario. Los índices no únicos no son parte de su modelo de datos; son simplemente una optimización.

PD: Benchmark InnoDB también, a menudo tiene un mejor rendimiento concurrente. Lo mismo con PostgreSQL.

Cuestiones relacionadas