Find_by_sql muy lento


#1

Al ejecutar esta consulta me tarda como 10 segundos sobre una base de
3600 registros, como puedo optimizar esta consulta ?

esta consulta la utilizo para buscar texto que coincida en 2 tablas
contacts y extencions.

@contacts = Contact.find_by_sql [" SELECT contacts.id[id],
contacts.name[name],
contacts.phone[phone],
contacts.address[address],
contacts.email[email],
contacts.category[category],
contacts.user_id[user_id],
contacts.note[note],
extencions.name[ext_name] FROM contacts, extencions where
contacts.user_id
= ?
and
(contacts.name LIKE ?
or
contacts.phone LIKE ?
or
contacts.address LIKE ?
or
contacts.email LIKE ?
or
contacts.category LIKE ?
or
contacts.note LIKE ? or extencions.name LIKE ? and contacts.id =
extencions.contact_id)
GROUP
BY contacts.id ORDER BY contacts.name LIMIT 50
",
session[:user_id], cadena, cadena, cadena, cadena, cadena, cadena,
cadena]


#2

@contacts = Contact.find_all_y_user_id.(session[:user_id],
:joins => [:extensions],
:include => [:extensions],
:conditions => ["contacts.name LIKE ? or contacts.phone LIKE ? or
contacts.address LIKE ? or contacts.email LIKE ? or contacts.category
LIKE ? or contacts.note LIKE ? or extencions.name LIKE ? ", cadena,
cadena, cadena, cadena, cadena, cadena],
:group => “id”,
:order => “name”,
:limit => 50)

y luego puedes hacer @contacts.first.extension.name sin coste, gracias
al include.

2009/5/26 Oscar D. removed_email_address@domain.invalid:


#3

Pror cierto, y pensando un poco mas, si “cadena” no tinen
ningúncaracter tipo ‘%’ mejor pon ‘=’ donde pones ‘like’

2009/5/26 LLeïr Borràs removed_email_address@domain.invalid:


#4

El día 26 de mayo de 2009 8:21, Oscar D.
removed_email_address@domain.invalid
escribió:> contacts.email[email],

                                                            or
                                                            ",

session[:user_id], cadena, cadena, cadena, cadena, cadena, cadena,
cadena]

Obviamente, la tardanza es un problema de SQL y no de rails.
¿Qué base de datos es?
A simple vista, deberías cerciorarte que el query esté bien … Yo
cerraría el paréntesis antes del and o usaría un inner join…

contacts.note LIKE ? or extencions.name LIKE ? ) and contacts.id =
extencions.contact_id

Silvio


#5

El día 26 de mayo de 2009 9:32, Silvio Q. removed_email_address@domain.invalid
escribió:>> contacts.address[address],

contacts.phone LIKE ?
BY contacts.id ORDER BY contacts.name LIMIT 50
contacts.note LIKE ? or extencions.name LIKE ? ) and contacts.id =
extencions.contact_id

Por cierto, si la base de datos va creciendo, tenés que pensar en una
solución “Full text search”, porque no va a haber motor de base de
datos que se banque una cosa
así.Silvio


#6

On 5/26/09, Oscar D. removed_email_address@domain.invalid wrote:

Al ejecutar esta consulta me tarda como 10 segundos sobre una base de
3600 registros, como puedo optimizar esta consulta ?

Hola,

Es más o menos sabido que las consultas con LIKE en MySQL son lentas
para conjuntos de datos grandes (puedes encontrar multitud de
variantes de esta afirmación en google). No sé si se puede considerar
grande una tabla con 3600 filas, pero en fin, tu problema
ahí está.
Alternativas que tienes:

  1. Como dice Lleir, cambiar LIKE por = donde te sea posible (y viendo
    que no utilizas el carácter % como comodín, es posible que puedas
    hacerlo en toda la consulta).

  2. Si estás en MySQL y con tablas myisam, puedes usar FULLTEX KEYS. No
    es una solución perfecta, sin duda te acopla, y tendrás que hacer
    alguna chapucilla ya que Rails no lo soporta directamente, pero
    funciona y ahí está http://www.google.es/search?q=mysql+full+text+keys

  3. La solución más chula pero también la que más cambios implica
    respecto a lo que estás haciendo es usar motores de búsqueda
    específicos. Mi experiencia con Sphinx y ThinkingSphinx es bastante
    satisfactoria http://www.sphinxsearch.com/
    http://freelancing-god.github.com/ts/en/

Espero que estas pistas te sirvan de ayuda, un saludo


Sergio Gil Pérez de la Manga
e-mail > removed_email_address@domain.invalid
blog > http://www.lacoctelera.com/porras
now > http://twitter.com/porras


#7

On 5/26/09, Sergio Gil Pérez de la Manga removed_email_address@domain.invalid wrote:

On 5/26/09, Oscar D. removed_email_address@domain.invalid wrote:

Al ejecutar esta consulta me tarda como 10 segundos sobre una base de
3600 registros, como puedo optimizar esta consulta ?

Hola,

Es más o menos sabido que las consultas con LIKE en MySQL son lentas
para conjuntos de datos grandes (puedes encontrar multitud de
variantes de esta afirmación en google)

Me estoy dando cuenta que he asumido que estabas usando MySQL a pesar
de que tú no lo decías, espero que las pistas te sean de igual
utilidad aunque yo haya metido la pata :wink:


Sergio Gil Pérez de la Manga
e-mail > removed_email_address@domain.invalid
blog > http://www.lacoctelera.com/porras
now > http://twitter.com/porras


#8

LLeïr Borràs wrote:

@contacts = Contact.find_all_y_user_id.(session[:user_id],
:joins => [:extensions],
:include => [:extensions],
:conditions => ["contacts.name LIKE ? or contacts.phone LIKE ? or
contacts.address LIKE ? or contacts.email LIKE ? or contacts.category
LIKE ? or contacts.note LIKE ? or extencions.name LIKE ? ", cadena,
cadena, cadena, cadena, cadena, cadena],
:group => “id”,
:order => “name”,
:limit => 50)

y luego puedes hacer @contacts.first.extension.name sin coste, gracias
al include.

2009/5/26 Oscar D. removed_email_address@domain.invalid:

Gracias por tu respuesta

Me tira el siguiente error

SQLite3::SQLException: ambiguous column name: name: SELECT “contacts”.*
FROM “contacts” INNER JOIN “extencions” ON extencions.contact_id =
contacts.id WHERE (contacts.name LIKE ‘%remis%’ or contacts.phone LIKE
‘%remis%’ or
contacts.address LIKE ‘%remis%’ or contacts.email LIKE ‘%remis%’ or
contacts.category
LIKE ‘%remis%’ or contacts.note LIKE ‘%remis%’ or extencions.name LIKE
‘%remis%’) AND (“contacts”.“user_id” = 1) GROUP BY id ORDER BY name
LIMIT 50

yo calculo que es por que tengo en ambas tablas campos con el nombre
name, en mi consulta yo especifico extencions.name[ext_name] como nombre
alternativo en tu consulta como lo hago ?

Utilizo Sqlite3


#9

es por el order by, pon :order => “contacts.name”

2009/5/26 Oscar D. removed_email_address@domain.invalid:


#10

LLeïr Borràs wrote:

es por el order by, pon :order => “contacts.name”

2009/5/26 Oscar D. removed_email_address@domain.invalid:

Muchas Gracias a todos, funciono perfecto !!!

se redujo el tiempo de búsqueda ahora es casi inmediato antes tardaba
como 10 segundos

La consulta quedo asi:

@contacts = Contact.find_all_by_user_id(session[:user_id],
:joins => [:extencions],
:include => [:extencions],
:conditions => [“contacts.name LIKE ? or contacts.phone LIKE ? or
contacts.address LIKE ? or contacts.email LIKE ? or contacts.category
LIKE ? or contacts.note LIKE ? or extencions.name LIKE ?”, cadena,
cadena, cadena, cadena, cadena, cadena, cadena],
:group => “contacts.id”,
:order => “contacts.name”,
:limit => 50)

Saludos a todos !!!


#11

2009/5/26 Sergio Gil Pérez de la Manga removed_email_address@domain.invalid

Me estoy dando cuenta que he asumido que estabas usando MySQL a pesar
de que tú no lo decías, espero que las pistas te sean de igual
utilidad aunque yo haya metido la pata :wink:

Mira que eres melón, Sergio


#12

LLeïr Borràs wrote:

conste que no he optimizado nada, lo �nica �s que hacer un inner join
entre dos tablas �s m�s �ptimo la mayoria de casos mientras que el
producto de las dos tablas requiere mas memoria y recursos.
Tienes indices puestos? Y est�n en el orden correcto?

2009/5/26 Oscar D. removed_email_address@domain.invalid:

Estuve leyendo documentación sobre los indices, pero no me quedo muy
claro

asi creo el indice pero como lo uso ? o en la consulta se usa
automaticamente ?

en la tabla contacts

CREATE INDEX mi_indice ON (name, phone)


#13

conste que no he optimizado nada, lo única és que hacer un inner join
entre dos tablas és màs óptimo la mayoria de casos mientras que el
producto de las dos tablas requiere mas memoria y recursos.
Tienes indices puestos? Y están en el orden correcto?

2009/5/26 Oscar D. removed_email_address@domain.invalid:


#14

2009/5/26 Oscar D. removed_email_address@domain.invalid:

asi creo el indice pero como lo uso ? o en la consulta se usa
automaticamente ?
Los indices se usan si estan disponibles y la consulta està bien hecha.


#15

2009/5/26 Dani D. removed_email_address@domain.invalid:

2009/5/26 Oscar D. removed_email_address@domain.invalid:

asi creo el indice pero como lo uso ? o en la consulta se usa
automaticamente ?
Los indices se usan si estan disponibles y la consulta està bien hecha.
se usan automaticamente quiero decir


#16

MySql y otros motores de bases de datos tienen un parseador de
sentencias, que intentan mejorar lo que tu escrives, giran el orden de
las condicions, elijen los mejores índices, … A menos que no lo
forces manualmente, si tienes indices bien definidos no te hace falta
decir nada para que actuen correctamente quando los necesites.

Para crear los indices mejor usar migraciones, del tipo
add_index :nombre_tabla, :nombre_campo, …

2009/5/26 Dani D. removed_email_address@domain.invalid:


#17

Dani D. wrote:

2009/5/26 Dani D. removed_email_address@domain.invalid:

2009/5/26 Oscar D. removed_email_address@domain.invalid:

asi creo el indice pero como lo uso ? o en la consulta se usa
automaticamente ?
Los indices se usan si estan disponibles y la consulta està bien hecha.
se usan automaticamente quiero decir

Encontre un problema en la consulta

solo me devuelve contactos que contengan extensiones

como hago para ver los contactos que no tienen extensiones también ?

es una consulta sobre una agenda la cual algunos contactos tiene
extensiones y otros no.

  cadena = "%" + params[:name] + "%"

  @contacts = Contact.find_all_by_user_id(session[:user_id],
              :joins => [:extencions],
              :include => [:extencions],
              :conditions => ["contacts.name LIKE ? or 

contacts.phone LIKE ? or
contacts.address LIKE ? or contacts.email LIKE ? or
contacts.category
LIKE ? or contacts.note LIKE ? or extencions.name LIKE
?", cadena,
cadena, cadena, cadena, cadena, cadena, cadena],
:group => “contacts.id”,
:order => “contacts.name”,
:limit => 50)


#18

Si lo tubiera que hacer con Sql meteria un left join en vez de un
inner join, pero con rails no he savido hacer-lo nunca, la unica
solucion que te puedo dar, que no es muy bonita pero funciona es

@contacts = Contact.find_all_by_user_id(session[:user_id],
:joins => [“left join extensions on
extensions.contact_id = contacts.id”],
:include => [:extencions],
:conditions => [“contacts.name LIKE ? or
contacts.phone LIKE ? or
contacts.address LIKE ? or contacts.email LIKE ? or
contacts.category
LIKE ? or contacts.note LIKE ? or extencions.name LIKE
?”, cadena,
cadena, cadena, cadena, cadena, cadena, cadena],
:group => “contacts.id”,
:order => “contacts.name”,
:limit => 50)

2009/5/26 Oscar D. removed_email_address@domain.invalid:


#19

On 5/26/09, Manuel González Noriega removed_email_address@domain.invalid
wrote:

Ay, ya me estaba pensando que ya no me querías, qué emoción, se me cae
la lagrimita :_)


Sergio Gil Pérez de la Manga
e-mail > removed_email_address@domain.invalid
blog > http://www.lacoctelera.com/porras
now > http://twitter.com/porras


#20

Sergio Gil Pérez de la Manga wrote:

On 5/26/09, Manuel Gonz�lez Noriega removed_email_address@domain.invalid
wrote:

Ay, ya me estaba pensando que ya no me quer�as, qu� emoci�n, se me cae
la lagrimita :_)


Sergio Gil P�rez de la Manga
e-mail > removed_email_address@domain.invalid
blog > http://www.lacoctelera.com/porras
now > http://twitter.com/porras

Ahora si !!! funciona perfecto

lo que no entiendo es por que decís que no es muy bonita que problemas
puede traer ?

  cadena = "%" + params[:name] + "%"

  @contacts = Contact.find_all_by_user_id(session[:user_id],
              :joins => ["left join extencions on 

extencions.contact_id = contacts.id"],
:include => [:extencions],
:conditions => [“contacts.name LIKE ? or
contacts.phone LIKE ? or
contacts.address LIKE ? or contacts.email LIKE ? or
contacts.category
LIKE ? or contacts.note LIKE ? or extencions.name LIKE
?”, cadena,
cadena, cadena, cadena, cadena, cadena, cadena],
:group => “contacts.id”,
:order => “contacts.name”,
:limit => 50)