menéame, novedades, pijadas

Otro RSS: de «conversaciones»

Vaya palabro, pero no se me ocurrió una mejor. Lo que quiere decir es que es un RSS de los comentarios de las noticias donde ha comentado cada usuario.

Está accesible en el menú de RSS, se llama «rss mis conversaciones» (sólo lo veréis si estáis autentificados, pero cambiando el código es posible seguir la de cualquier usuario, si sabéis su id).

Es algo que nos lo pedían repetidamentre (la última hace unas horas), hoy me decidí a ponerle, y pedir ayuda a encontrar el select con un «inner join» que hiciese el trabajo «como toca». Lo lograron Friki y Moof, gracias:

SELECT DISTINCT comments1.comment_id FROM comments AS comments1 INNER JOIN comments AS comments2 WHERE comments1.comment_link_id = comments2.comment_link_id AND comments2.comment_user_id=$id AND comments2.comment_date > $from_time order by comments1.comment_id desc LIMIT $rows

14 comentarios en “Otro RSS: de «conversaciones»

  1. Me da miedo darte consejos de programación tras aquel atentado que sufrí cuando sugerí lo de convertir IPs de cadenas a enteros, pero por si te sirve de algo, cuando trabajaba en esas otras empresas que ya sabes, lo de hacer JOINs era considerado casi un pecado. Y no lo decía yo, que de DBA tengo lo justo y a malas penas. Creo que mysql es mas suave con los joins que esa otra base de datos tan famosa, pero bueno, ahí dejo el comentario por si sirve de algo.

  2. DN

    Creo que el sistema tiene un pequeño bug. Cuando te suscribes a los comentarios de un usuario que lleva mucho tiempo sin tener actividad, el servidor devuelve una página en blanco diciendo «no hay cambios».

    La solución, es realizar un comentario con ese usuario y listo.

    La solución buena, es comprobar si es la primera vez que se solicita la página para devolver un rss vacío, o un rss diciendo que no hay cambios desde la última vez.

  3. renegm

    No se que querrá decir RBA con considerar un pecado las join cuando toda la idea relacional se basa en ello.
    Pero en esta consulta hay 2 detalles. Yo no estoy seguro de cuan “inteligente” sea el MySQL al tratar joins escritas en SQL-89, pero por mera “estética” (y rendimiento si el motor puede confundirse al hacer el plan de ejecución) es preferible usar este formato: INNER JOIN comments AS comments2 ON comments1.comment_link_id = comments2.comment_link_id
    El segundo detalle es el uso del SELECT DISTINCT. Yo hubiese utilizado GROUP BY, porque las funciones de agregados suelen estar mejor optimizadas, pero valdría la pena probarlo.

  4. renegm, acabo de probar lo que me dices, y los números que da el mysql son exactamente iguales (tanto en tiempo como con el EXPLAIN) para la misma consulta.

    Lo del group tengo que ver cómo lo preparo para probar y asegurar que sean distintos (según los manuales, optimiza muy bien con el distinct).

    Los tiempos que me da esta consulta para 90 días de comentarios es de 0.84 segundos para la primera vez, 0.13 para las siguientes (con el SQL_NO_CACHE).

    Paar hacer lo mismo con sub select tarda casi un minuto (resuelve primero siempre el externo y luego para cada fila verifica el interno), por eso tenía que buscar la forma de hacerlo con el inner join.

  5. DN

    Hola Ricardo… ya se que el error es MUY raro… y que lo expliqué mal… pero falla… y por lo que dice Álvaro yo no soy el único.

    Pero, esta vez voy a pasarte datos.

    Intento suscribirme a las noticias del usuario 3 (no se quien es, pero creo que lleva inactivo un tiempo). Y estas son las cabeceras que le envió/devuelve:

    ENVIO –> http://meneame.net/comments_rss2.php?conversation_id=3
    GET /comments_rss2.php?conversation_id=3 HTTP/1.1
    Host: meneame.net
    User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0
    Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
    Accept-Language: es,en;q=0.7,es-es;q=0.3
    Accept-Encoding: gzip,deflate
    Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
    Keep-Alive: 300
    Connection: keep-alive
    Cookie: — censurado 😉 —

    DEVUELVE –>
    HTTP/1.x 304 Not Modified
    Date: Mon, 18 Dec 2006 15:52:46 GMT
    Server: Apache/2.2.3 (Debian) PHP/5.2.0-7
    Connection: Keep-Alive
    Keep-Alive: timeout=2, max=100
    Vary: Accept-Encoding

    Lógicamente es la primera vez que me conecto a esa url. La página siempre devuelve el 304. No es culpa de ningún proxy ya que si añado esa url a Google Reader, me la rechaza porque dice que no es un RSS válido.

    Antes mi usuario de menéame se comportaba de la misma forma que el usuario 3… porque llevaba bastante tiempo sin actividad… pero desde que comenté una noticia, ahora devuelve un rss de forma correcta.

    Espero que ahora lo haya explicado correctamente… si no consigues reproducirlo, por favor hazmelo saber.

  6. DN

    Antes se me olvidó comentar un par de cosas sobre la consulta de sql…

    Me parece interesante lo que cuenta RBA sobre lo poco que les gustaba en ebay los joins… pero creo que esa norma no se debería aplicar al diseño de menéame. Me explico.

    En ebay, tienen muchos servidores web, pero solo una única base de datos sobre un servidor Oracle/unix enorme… que puede a duras penas con su trabajo. Como es complicado ampliar esa máquina, un diseño inteligente nos obligaría a hacer consultas siempre muy sencillas, para que el oracle no consuma procesador «tontamente», y en los servidores web es donde podemos hacer el procesamiento de los datos. Si en algún momento tenemos problemas de procesamiento se añade una máquina «web» y listo.

    En menéame solo hay una única máquina. Base de datos y web están juntas, es decir… el join se realice en SQL o en código, se lo chupará el procesador de nuestra máquina… en este caso la lógica dice, que lo mejor es que se encargue de hacer el join el software especialista en datos.

    En cuanto a si es mejor usar una subconsulta, un inner o lo que sea… me parece muy bien hablar de alternativas… pero es especular por especular. La única forma de saber si una cosa es mejor o otra es probándola en esa base de datos. Si una consulta funciona bien en un gestor, no tiene porque funcionar en otro gestor.

    Esto lo digo por experiencia, tengo usado consultas que en SQL Server iban muy bien, usando sus índices correctamente, pero cuando se pasaron a Oracle ni usaban índices ni ná, de na.

  7. renegm

    No me sorprende que te devuelva el mismo tiempo. Casi todos los motores son capaces de interpretar adecuadamente las Join, por eso dije “estética”. Pero en consultas muy complejas (esta no lo es) se corre el riesgo de que el motor ejecute primero el Join y luego el filtro si se hace con Where, porque interpreta literalmente lo que se le pide. ON evita esto.

    La consulta con Group By debería ser esta:
    SELECT comments1.comment_id FROM comments AS comments1 INNER JOIN comments AS comments2 ON comments1.comment_link_id = comments2.comment_link_id AND comments2.comment_user_id=$id AND comments2.comment_date > $from_time GROUP BY comments1.comment_id order by comments1.comment_id desc LIMIT $rows

    No garantizo que mejore el resultado. Tanto SQL Server como Oracle me proponen exactamente el mismo plan para ambas consultas. Yo prefiero usar funciones de agregados porque me he tropezado varias veces con scaneos inútiles cuando uso distinct. Lo del ON en las Join es casi cosmético 🙂

  8. DN, ya revisé el código y reorganizado y afinado el control de cabeceras, ahora seguro que te debería ir bien (probé con todos los clientes que tengoa mano, incluso con wget y header=»If-Modified-Since..:» http://svn.meneame.net/index.cgi?rev=225&view=rev

    El usuario nro 3 no tiene ninguna «conversación» en los últimos días, y te devolverá siempre un RSS con las cabeceras y footers correctos, pero sin ningún item (así deberías verlo).

    Bueno, ya me dirás si te funciona.

    Gracias.

  9. renegm,

    genial la consulta, lo acabo de probar, me da exactamente los mismos tiempos, 0.03 segundos para 31 días y el usuario 1 (que soy yo).

    O sea que al menos en eso el mysql es consistente.

  10. renegm

    >DN Si una consulta funciona bien en un gestor, no tiene porque funcionar en otro gestor.
    Mmm Yo creo que los standares deben servir para algo. Un motor puede hacer más o menos hincapié en una u otra cosa pero no “pasarse de listo”. Si una consulta sigue los standares y un “truco” la mejora, el motor tiene problemas. Todavía recuerdo las consultas: SELECT Max(x), Min(x) from Tabla que necesitaban ser ¿optimizadas? a SELECT Max(x), (SELECT Min(x) from Tabla) from Tabla .

    Ricardo. No sé como probaste la subconsulta, Pero esto deberia comportarse igual de bien:

    SELECT comment_id FROM comments INNER JOIN
    (SELECT comment_link FROM comments WHERE comment_user_id=$id AND.comment_date > $from_time) AS comments2 ON comments1.comment_link_id = comments2.comment_link_id id order by comments1.comment_id desc LIMIT $rows

    Y esto otro, ya tiene motivos para no ser tan bueno: usar la subconsulta dentro del where:
    WHERE comment_link_id IN (select…)
    Aunque hay motores más generosos que otros:)
    Y MySQL está cada vez mejor, Ya estoy a punto de migrar 🙂

Este sitio utiliza Akismet para reducir el spam. Conoce cómo se procesan los datos de tus comentarios.