Performance: select vs pluck vs select_values vs raw sql
Après une discussion sur le Slack de Paris.rb à propos des perfs des requêtes Active Record vs raw SQL, j’ai refait un rapide benckmark des solutions qu’on a lorsqu’on veut extraire beaucoup de données d’une base pour effectuer des opération dessus. Comme par exemple sortir des rapports, tracer des graphiques etc.
Pour l’opération, j’ai pris un simple *2 qui n’est là que pour l’exemple mais j’en ai profité pour comparer aussi les temps de cette multiplication entre l’exécution sur le serveur ruby ou sur le serveur de base de données.
Tests réalisés pour 250 et 100k records, en sqlite et PostgreSQL.
250 records, en local, sqlite
On voit sans grande surprise que le select prend largement plus de temps.
100k, en local, sqlite
Voyons ce que ça donne avec 100k éléments, toujours sur un sqlite en local :
Comme les opérations prennent significativement plus de temps, j’ai dû réduire le nombre d’itération (je t’ai dis que c’était un bench rapide 😛).
Le select prend presque 3 fois plus de temps que le raw sql
pluck et select_values sont clairement plus intéressants ici. Je ne m’étend pas plus dessus ça reste du sqlite.
100k, PostgreSQL, Heroku
Mais comme on sait bien qu’un sqlite en local ne représente pas la réalité de l’app qu’on aura en prod, voilà le même test sur un heroku (free dyno) + pqsql (hobby dev), toujours avec 100k records :
On retrouve toujours des temps pour select » (raw sql et pluck) > select_values. Par contre, la multiplication est maintenant plus lente via pgsql que via ruby. J’ai envie de mettre ça sur le dos de la base peut-être un peu lente en version gratuite chez Heroku.
100k, MySQL, local
[EDIT]: J’ajoute le même bench sur MySQL à la demande de @alexnarb et sous forme de tableau cette fois 🙂
On reste sur la même conclusion qu’avant.
Si tu es attentif, tu as vu que j’utilise exec_query au lieu de execute pour MySQL. Pourquoi ? execute ne renvoie pas les résultats de la requête quand on utilise l’adaptateur mysql2.
Mais alors, il y a une différence de perf entre les 2 sur du pgSQL ? Oui, moi aussi je me suis posé la question (toujours sur heroku, 100k records).
L’écart n’est pas énorme, j’ai relancé le bench plusieurs fois et on tourne autours de 10%.
Conclusion et TL;DR
⚠️ attention, j’enfonce des portes ouvertes
Ça vaut le coup de prendre 5 min pour faire un bench avec un grand nombre de records
Il vaut mieux éviter les select et préférer pluck ou mieux select_values
Il faut faire le bench sur la même techno de base que la prod