Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment Rails construit-il une instruction MySQL ?

essayer sql ?

S'il ne s'agit que de cette seule instruction et qu'elle cause des problèmes de production, pouvez-vous omettre le générateur de requêtes pour le moment ? En d'autres termes, à très court terme, écrivez simplement le SQL vous-même. Cela vous fera gagner un peu de temps.

# All on one line:
Artist.find_by_sql
  "SELECT `artists`.* FROM `artists` 
   WHERE `artists`.`id` = #{params[:artist_id].to_i} LIMIT 1"

ARel/MySQL expliquer ?

Rails peut aider à expliquer ce que MySQL essaie de faire :

Artist.find(params[:artist_id]).explain

http://weblog.rubyonrails.org/2011/12/6/what-s-new-in-edge-rails-explain/

Peut-être pouvez-vous découvrir une sorte de différence entre les requêtes qui réussissent et celles qui échouent, comme la façon dont le explain utilise des index ou des optimisations.

la gemme mysql2 ?

Pouvez-vous essayer de passer de la gemme mysql à la gemme mysql2 ? Quel échec obtenez-vous lorsque vous passez à la gemme mysql2 ?

volatilité ?

Peut-être y a-t-il autre chose qui modifie le hachage des paramètres à la volée, donc vous le voyez lorsque vous l'imprimez, mais il a changé au moment où la requête s'exécute ?

Essayez d'affecter la variable dès que vous recevez les paramètres :

artist_id = params[:artist_id]
... whatever code here...
@artist = Artist.find(artist_id)

pas le hachage des paramètres ?

Vous avez écrit "Ce qui signifie que Rails ne passe pas dans le params[:artist_id] qui est évidemment dans le hachage params." Je ne pense pas que ce soit le problème - je suppose que vous voyez cela parce que Rails utilise le "?" comme espace réservé pour une déclaration préparée.

Pour le savoir, lancez les commandes suggérées par @Mori et comparez-les; ils devraient être identiques.

Article.find(42).to_sql
Article.find(params[:artist_id]).to_sql

déclarations préparées ?

Il peut s'agir d'un problème de cache d'instructions préparées, lorsque la requête est réellement exécutée.

Voici le code qui échoue - et il y a un gros avertissement.

begin
  stmt.execute(*binds.map { |col, val| type_cast(val, col) })
rescue Mysql::Error => e
  # Older versions of MySQL leave the prepared statement in a bad
  # place when an error occurs. To support older mysql versions, we
  # need to close the statement and delete the statement from the
  # cache.
  stmt.close
  @statements.delete sql
  raise e
end

Essayez de configurer votre base de données pour désactiver les instructions préparées, pour voir si cela fait une différence.

Dans votre ./config/database.yml fichier :

production:
   adapter: mysql
   prepared_statements: false
   ...

des bogues avec des instructions préparées ?

Il peut y avoir un problème avec Rails ignorant ce paramètre. Si vous voulez en savoir plus à ce sujet, consultez cette discussion et correction de bogue par Jeremey Cole et Aaron :https://github.com/rails/rails/pull/7042

Heroku peut ignorer le paramètre. Voici un moyen d'essayer de remplacer Heroku en corrigeant la configuration de ready_statements :https://github.com /rails/rails/issues/5297

supprimer le cache des requêtes ?

Essayez de supprimer ActiveRecord QueryCache pour voir si cela fait une différence :

config.middleware.delete ActiveRecord::QueryCache

http://edgeguides.rubyonrails.org/configuring.html#configuring-middle

essayer postgres ?

Si vous pouvez essayer Postgres, cela pourrait aussi le clarifier. Ce n'est peut-être pas une solution à long terme pour vous, mais cela isolerait le problème de MySQL.