Problema con uso de indices

Holas,

Tengo un problemilla definiendo un indice y no se si es que se me ha
pasado algo o que simplemente no se puede hacer. Os cuento:

Simplificando tengo un modelo:

class Photo < ActiveRecord::Base
belongs_to :article
end

y el modelo article:

class Article < ActiveRecord::Base
has_many :photos, :dependent => :destroy
end

Y el indice creado de la siguiente manera:

add_index :photos, [ :article_id ], :name => “idx_photos_article_id”

(Para ver que tal andan las querys si usan indices o no por abajo
estoy usando los plugins query_reviewer y newrelic.)

Pues bien haciendo una query sobre los articulos con:

Photo.find(:all, :conditions => [“article_id = ?”, 1])

por ejemplo si que se usa el indice y va perfecto.

Pero cuando intento hacer:

Articulo.find(:all, :include =>[:photos])

para sacar las fotos y ahorrarme querys no funciona el indice.

¿Alguien tiene idea que se me está escapando?

Saludos
Felipe T.

Hola Felipe,

2008/9/18 Felipe T. Armero [email protected]

(Para ver que tal andan las querys si usan indices o no por abajo
Articulo.find(:all, :include =>[:photos])
pienso que es por lo que al usar eso te esta generando 2 consultas:

SELECT * FROM Articulos
SELECT * FROM photos WHERE id IN(1,2,3…ultimo_id_de_articulos)

Entonces como ves, en la segunda consulta ya de por si esta usando el
indice
que es la clave primaria, por lo cual el indice que tu has creado no
entra a
jugar y esa consulta sigue siendo eficiente.

http://lists.simplelogica.net/mailman/listinfo/ror-es

Saludos

On Sep 18, 2008, at 11:17 PM, Ruben. D. wrote:

class Photo < ActiveRecord::Base

el indice que es la clave primaria, por lo cual el indice que tu has
creado no entra a jugar y esa consulta sigue siendo eficiente.

Efectivamente, se genera el select de articulos, pero la segunda es
distinta:

SELECT photos.* FROM photos WHERE (photos.articulo_id IN
(29,26,23,20,17,14,11,8,5,2,30,27,24,21,18,15,12,9,6,3,28,25,22,19,16,13,10,7,4,1
))

según la consulta debería estar usando mi indice no el de la clave
primaria, pero mi mosqueo viene por los warning que me dan los dos
plugins. algo raro pasa, con las consultas o con los plugins…

Felipe T. Armero wrote:

On Sep 18, 2008, at 11:17 PM, Ruben. D. wrote:

class Photo < ActiveRecord::Base

el indice que es la clave primaria, por lo cual el indice que tu has
creado no entra a jugar y esa consulta sigue siendo eficiente.

Efectivamente, se genera el select de articulos, pero la segunda es
distinta:

SELECT photos.* FROM photos WHERE (photos.articulo_id IN
(29,26,23,20,17,14,11,8,5,2,30,27,24,21,18,15,12,9,6,3,28,25,22,19,16,13,10,7,4,1
))

seg�n la consulta deber�a estar usando mi indice no el de la clave
primaria, pero mi mosqueo viene por los warning que me dan los dos
plugins. algo raro pasa, con las consultas o con los plugins…

Si no quieres que te lo haga en dos consultas, sino que utilice el
índice, utiliza join en vez de include:

Articulo.find(:all, :joins => “inner join photos p on p.articulo_id =
articulo.id”)

O no sé si funciona esto:

Articulo.find(:all, :joins => :photos)

s2

On Sep 19, 2008, at 10:26 AM, Fernando C. wrote:

Si no quieres que te lo haga en dos consultas, sino que utilice el
índice, utiliza join en vez de include:

Articulo.find(:all, :joins => “inner join photos p on p.articulo_id =
articulo.id”)

O no sé si funciona esto:

Articulo.find(:all, :joins => :photos)

El problema no es la segunda consulta, es que la segunda no usa el
indice, prefiero hacer una consulta mas que meter un join, aunque he
probado con el join y tampoco funciona
así.

Ops, tienes razon Feilpe, me equivoque, pero cual es la salida del
EXPLAIN?

Saludos.

On Fri, Sep 19, 2008 at 12:01, Felipe T. Armero
[email protected] wrote:

O no sé si funciona esto:

Articulo.find(:all, :joins => :photos)

El problema no es la segunda consulta, es que la segunda no usa el
indice, prefiero hacer una consulta mas que meter un join, aunque he
probado con el join y tampoco funciona así.

Según
http://dev.mysql.com/doc/refman/5.1/en/how-to-avoid-table-scan.html
es posible que en algunos casos MySQL elija hacer un full table scan
en vez de utilizar un índice dependiendo de las tablas. Sobre todo
supongo que se te aplica esto:

“You are comparing indexed columns with constant values and MySQL has
calculated (based on the index tree) that the constants cover too
large a part of the table and that a table scan would be faster. See
Section 7.2.4, “WHERE Clause Optimization”.”

También viene como forzar a MySQL a utilizar un índice: FORCE INDEX
(indice)

Yo copiaría el SELECT que genera Rails y lo ejecutaría en la consola
de MySQL anotando los tiempos, le incluiría el FORCE INDEX y volvería
a ejecuar y compararía si MySQL está “desoptimizando para optimizar” o
la está fastidiando (repetir las pruebas una docena de veces para
estar seguros de los números).

Suerte.

table select_type type extra possible_keys key key
length
ref rows
photos simple all using where idx_photos_article_id
1

sale como possible_key pero no como la key elegida, sabe que está ahi
pero pasa de usarla.

Comentar que es bastante útil activar el slow queries log de MySQL
para ver si hace falta meter índices.

On 19/09/2008, at 13:24, Felipe T. Armero

On Sep 19, 2008, at 12:28 PM, Daniel R. Troitiño wrote:

También viene como forzar a MySQL a utilizar un índice: FORCE INDEX
(indice)

Yo copiaría el SELECT que genera Rails y lo ejecutaría en la consola
de MySQL anotando los tiempos, le incluiría el FORCE INDEX y volvería
a ejecuar y compararía si MySQL está “desoptimizando para optimizar” o
la está fastidiando (repetir las pruebas una docena de veces para
estar seguros de los números).

Suerte.

Vale, ya está solucionado.

La tabla photos que tenia de pruebas, no tenia suficientes registros y
pasaba lo que tu comentas, que mysql no usaba el indice.

Ha sido meterle unos miles de registros y todo ha empezado a funcionar
a la perfección, usando el indice tal y como estaba.

Gracias por la ayuda

Saludos
Felipe

Algo como lo que comenta Daniel habia leido sobre Mysql, osea que cuando
tienes pocos registros y la consulta que haces hace referencia a muchos
de
esos registros entonces Mysql cree conveniente que un escaneo completo
de la
tabla es mas eficiente, por eso no me causo mucha alarma cuando vi que
query_reviewer me tiraba falsos positivos, de todas maneras aqui un
material
mas de ayuda:

http://www.mysql-hispano.org/page.php?id=29

Saludos.