Top Banner
Revenge of the ORMs Why SQL skills still matter in 2015 Lightning strikes © flickr.com/photos/snowpeak CC-BY
40

Revenge of the ORMs

Aug 18, 2015

Download

Software

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Revenge of the ORMs

Revenge of the ORMs

Why SQL skills still matter in 2015

Lightning strikes © flickr.com/photos/snowpeak CC-BY

Page 2: Revenge of the ORMs

First, An Intro

Page 3: Revenge of the ORMs

Megan Bowra-Dean !• Rails/JS/Android/iOS/

kitchen sink developer at Rabid Tech

• 2 years .NET enterprise web dev

• 2 years C/C++ embedded dev

• Ruby NZ Committee Member

Page 4: Revenge of the ORMs

–Roy Batty, Bladerunner

“I've seen things you people wouldn't believe.”

Page 5: Revenge of the ORMs

Reintroducing ORMs

Page 6: Revenge of the ORMs

ORMs

• “Object Relational Mappers”

• Translates and serialises objects to a relational database

• Generally database agnostic

Page 7: Revenge of the ORMs

Cat.new(fur: 'calico', name: 'Ms Tibbles')

id fur name

1 calico Ms Tibbles

Page 8: Revenge of the ORMs

ms_tibbles.owner = Owner.new(name: 'Megan')

id fur name owner_id

1 calico Ms Tibbles 1

cats table

id name

1 Megan

owners table

Page 9: Revenge of the ORMs

Examples

Entity FrameworkActiveRecord django.db

Page 10: Revenge of the ORMs

The Good 👍

Page 11: Revenge of the ORMs

Saves development time & easier to maintain

SELECT * FROM books INNER JOIN libraries ON books.library_id = libraries.id WHERE libraries.name = 'Wellington City Library'

Book .joins('libraries') .where(libraries: { name: 'Wellington City Library' })

VS

Page 12: Revenge of the ORMs

Security

• Most ORMs stop SQL injection attacks 💉

• Some restrict columns that can be updated by user input (e.g. Rails 4’s strong_params)

Page 13: Revenge of the ORMs

BUT $

Page 14: Revenge of the ORMs

When and How ORMs Can Breakdown

Page 15: Revenge of the ORMs

Ultimately ORMs are an Abstraction

• Simplified for specific use cases

• What happens when the relationships between your models get more complex?

• What happens when you need data not tied to a model’s fields? 📊

Page 16: Revenge of the ORMs

N+1 Problem

A book has an editor and magazines are a type of book, how do we find all the editors belonging to

magazines to print them out?

📚'(

Page 17: Revenge of the ORMs

Naive Way

magazines = Book .where(type: 'magazine')

magazines.each do |magazine| puts magazine.editor end

Page 18: Revenge of the ORMs

Resultant SQL

SELECT * FROM books WHERE type = 'magazine'

SELECT * FROM editors WHERE book_id = 1 SELECT * FROM editors WHERE book_id = 2 .. SELECT * FROM editors WHERE book_id = n

Page 19: Revenge of the ORMs

We end up with 1 + n queries, where n is the number of magazines, hence the N+1 problem.

Page 20: Revenge of the ORMs

Optimised Way

magazines = Book .includes('editor') .where(type: 'magazine')

magazines.each do |magazine| puts magazine.editor end

Page 21: Revenge of the ORMs

Resultant SQL

SELECT * FROM books WHERE type = 'magazine'

SELECT * FROM editors WHERE (book_id IN (1,2,3..n))

Page 22: Revenge of the ORMs

• Not always as obvious as this

• Can have a lot of things happening between fetching the parent model and the child models

• Still, (most) ORMs have the capability to help

Page 23: Revenge of the ORMs

Modern Scripting Languages are SLOW* 🐢

* At handling large data sets

Page 24: Revenge of the ORMs

• Page load times can slow down noticeably with just a few thousand instances of models.

• May expect to run operations on hundreds of thousands.

• Is it WEBSCALE?

Page 25: Revenge of the ORMs

We Usually Deal With This by Over-engineering

• Adding extra caching layers

• Load balancing with horizontal scaling

• Progressive page loading

Page 26: Revenge of the ORMs

Subverting Your ORM for Fun and Profit

Page 27: Revenge of the ORMs

• We can wrest the raw database connection from the ORM

• With this we can improve performance without greatly increasing complexity

Page 28: Revenge of the ORMs

A real world example

• Web app for client that surveyed organisational performance

• Produced an online report with several different breakdowns of statistics from the survey

• Was surprisingly slow - hit web server timeout

Page 29: Revenge of the ORMs

Looking closerMost of the time spent outside of the database

Page 30: Revenge of the ORMs

• 100,532 calls to Class#new ‼

• A simple page was only creating ~900 objects

• One suspect was a function calculating the average of responses to a group of questions (a “domain”)

Page 31: Revenge of the ORMs

sum = 0.0 count = 0.0 domain.questions.each do |q| response = q.response_for(respondent) sum += response.value count += 1.0 end

if count > 0 return sum / count else return 1.0 end

Page 32: Revenge of the ORMs

conn = ActiveRecord::Base.connection result = conn.execute <<-SQL SELECT SUM(responses.value) as sum, COUNT(*) as count FROM domains INNER JOIN questions ON questions.domain_id = domains.id INNER JOIN responses ON responses.question_id = questions.id AND responses.respondent_id = #{respondent.id} WHERE domains.id = #{domain.id} SQL

score = 1.0

sum = result[0]['sum'].to_f count = result[0]['count'].to_f

score = sum / count if count > 0

Page 33: Revenge of the ORMs

• Reduced page load time by more than a half

• Reduced number of objects created by 30%

Page 34: Revenge of the ORMs

Words of Caution ⚠

Page 35: Revenge of the ORMs

• Not as maintainable

• Need to keep an eye on security. Never insert user provided values into raw SQL.

• Not as portable.

XKCD #327 https://xkcd.com/327/

Page 36: Revenge of the ORMs

sql = Cat.where(name: 'Ms Tibbles').to_sql ActiveRecord::Base.connection.execute sql

Can sometimes get ORM to help you defeat itself

Page 37: Revenge of the ORMs

Cool Things Beyond Performance 😎

Page 38: Revenge of the ORMs

• Database functions

• Common table expressions

• Views

• GIS extensions for geographical data 🌏

• Non-standard data types

Page 39: Revenge of the ORMs

Finally: Remember your

indexes!

Page 40: Revenge of the ORMs

To Summarise

• ORMs bring great benefits much of the time

• However being aware of what they’re doing is essential

• If need be, it is possible to work around them.

• Databases are your friend.