Mysql to mongo

63
MYSQL TO MONGO (FTW) Thinking Differently About Schema Design

description

Slides for Presentation given at MongoLA on January 13, 2011 at Media Temple.

Transcript of Mysql to mongo

Page 1: Mysql to mongo

MYSQL TO MONGO (FTW)Thinking Differently About Schema Design

Page 2: Mysql to mongo

@AJSHARP

Alex SharpLead Developer, OptimisCorp

alexjsharp.com

github.com/ajsharp

Page 3: Mysql to mongo

Side project

CVBEAST

interested more in domain modeling more than performance and scaling benefits of Mongo

Mongo has many cool features such as schema-free, aggregation w map/reduce and many others

EMBEDDED OBJECTS

Page 4: Mysql to mongo

App to represent people’s curriculum vitae, but not in an academic sense

CVBEAST

Page 5: Mysql to mongo

Focus on “micro” experiences not suitable for a typical CV (definitely not suitable for a resumé)

CVBEAST

Page 6: Mysql to mongo

Simple object model, centered around highlighting attributes of a person

CVBEAST

Page 7: Mysql to mongo

Started out building with MySQL, b/c it’s familiar

CVBEAST

Page 8: Mysql to mongo

OBJECT MODELPerson

CV

Experience

has a

has many

has many

... ... ...

Page 9: Mysql to mongo

OBJECT MODELPerson

CV

Experience

has a

has many

has many

... ... ...

links, tags, and other arbitrary

properties

Page 10: Mysql to mongo

RELATIONAL SCHEMApeople - id - name - ... cvs - id - person_id - ... experiences - id - cv_id - ...

Page 11: Mysql to mongo

Lots of pointless JOINs

RELATIONAL SCHEMA

Page 12: Mysql to mongo

RELATIONAL SCHEMApeople - id - name - ... cvs - id - person_id - ... experiences - id - cv_id - ...

Page 13: Mysql to mongo

RELATIONAL SCHEMApeople - id - name - ... cvs - id - person_id - ... experiences - id - cv_id - ...

links - id - name - ...

tags - id - name - ...

Page 14: Mysql to mongo

this bothers me

not b/c of premature optimization

Page 15: Mysql to mongo

It misrepresents the object model at the storage layer

Page 16: Mysql to mongo

It also became difficult to work withdespite my familiarity with MySQL

Page 17: Mysql to mongo

It makes sense to store object relationships in first-class entities/documents/tables

Page 18: Mysql to mongo

But true object properties should be stored as properties

Page 19: Mysql to mongo

Not relationships.

Page 20: Mysql to mongo

Especially when properties have no practical meaning without the parent

Page 21: Mysql to mongo

This is not always the case.

;-)

CAVEAT

if you need to:* store LOTS of embedded objects (i.e. papermill)

Page 22: Mysql to mongo

EXAMPLEExperience Links

Page 23: Mysql to mongo

EXPERIENCE.LINKS = [...]

Dead-simple collection of links attached to an experience

Page 24: Mysql to mongo
Page 25: Mysql to mongo

class Person include Mongoid::Document

field :keywords, :type => Array

index :keywords index 'cv.experiences.tags'end

RUBY MODEL CODE

Page 26: Mysql to mongo

class Experience include Mongoid::Document

embeds_many :linksend

class Link include Mongoid::Document

field :url field :title embedded_in :experience, :inverse_of => :linksend

Page 27: Mysql to mongo

class Experience include Mongoid::Document

embeds_many :linksend

class Link include Mongoid::Document

field :url field :title embedded_in :experience, :inverse_of => :linksend

Both models are embedded in the person collection

Page 28: Mysql to mongo

EXPERIENCE.LINKS = [...]

A link is only relevant inside the context of an experience object.

Page 29: Mysql to mongo

EXPERIENCE.LINKS = [...]

In other words, it is a property,not a relationship.

Page 30: Mysql to mongo

EXPERIENCE.LINKS = [...]

Mongo brings the storage layer closer tothe object model

Page 31: Mysql to mongo

{ "title": "Presented at MongoLA", "links": [ { "title": "Event Site", "url": "http://www.10gen.com/conferences/mongola2011"}, { "title": "Slides", "url": "http://alexjsharp.com/posts/mongola-2010-slides"} ]}

EXPERIENCE.LINKS = [...]

Page 32: Mysql to mongo

Embedded SearchEXAMPLE

Page 33: Mysql to mongo
Page 34: Mysql to mongo

An exercise in masochismMYSQL

Page 35: Mysql to mongo

The difficulty in MySQL came in working with properties of a person

Page 36: Mysql to mongo

These properties are represented as tables

Page 37: Mysql to mongo

And tables must be joined

Page 38: Mysql to mongo

SIMPLE SEARCH QUERYselect * from people inner join cvs on cvs.person_id = people.id inner join experiences on experiences.cv_id = cvs.id inner join tags on tags.experience_id = experiences.id where tags.name = 'ruby';

Page 39: Mysql to mongo

INDEXES NEEDED- tags.experience_id- tags.name- experiences.cv_id- cvs.person_id

Page 40: Mysql to mongo

Seems extremely unnecessary for such a simple object model

Page 41: Mysql to mongo

An exercise in ... not masochismMONGO

Page 42: Mysql to mongo

Embedded objects make this query easy.

Page 43: Mysql to mongo

{"name": "Alex Sharp", "cv": { "experiences": [ { "title": "spoke at MongoLA", "date" : "Thu Jan 13 2011", "tags" : ["mongodb", "speaking"] }, {"title": "..."} ] }}

MONGO DOCUMENT “SCHEMA”

Page 44: Mysql to mongo

{"name": "Alex Sharp", "cv": { "experiences": [ { "title": "spoke at MongoLA", "date" : "Thu Jan 13 2011", "tags" : ["mongodb", "speaking"] }, {"title": "..."} ] }}

we want to search for these

MONGO DOCUMENT “SCHEMA”

Page 45: Mysql to mongo

class Person include Mongoid::Document

field :keywords, :type => Array

index :keywords index 'cv.experiences.tags'end

RUBY MODEL CODE

Page 46: Mysql to mongo

RUBY MODEL CODEclass Cv include Mongoid::Document

embeds_many :experiences end

class Experience include Mongoid::Document

field :tags, :type => Array, :default => []

embedded_in :cv, :inverse_of => :experiences embeds_many :links

after_save lambda { |exp| exp.cv.person.update_keywords }end

Page 47: Mysql to mongo

RUBY MODEL CODEclass Cv include Mongoid::Document

embeds_many :experiences end

class Experience include Mongoid::Document

field :tags, :type => Array, :default => []

embedded_in :cv, :inverse_of => :experiences embeds_many :links

after_save lambda { |exp| exp.cv.person.update_keywords }end

simple property(not relationship)

Page 48: Mysql to mongo

RUBY SEARCH CODE

class Person

# i.e. db.people.find({"cv.experiences.tags": "ruby"}) def self.search_by_tag(term) collection.find('cv.experiences.tags' => 'ruby') end

end

Page 49: Mysql to mongo

COMPARISONselect * from people inner join cvs on cvs.person_id = people.id inner join experiences on experiences.cv_id = cvs.id inner join tags on tags.experience_id = experiences.id where tags.name = 'ruby';

db.people.find('cv.experiences.tags' => 'ruby')

vs

Page 50: Mysql to mongo

WINS: IMPEDENCE MIS-MATCH

Object persistence format is closer to application usage format

Page 51: Mysql to mongo

WINS: F(X)-ALITY

Plus, we don’t lose any functionality.

Page 52: Mysql to mongo

WINS: FAMILIARITY

Indexing principles are extremely familiar to relational database users.

Page 53: Mysql to mongo

WINS: FAMILIARITY

Only simpler ;)

Page 54: Mysql to mongo

WINS: SIMPLICITY

Query syntax is simple.

Page 55: Mysql to mongo

WINS: SIMPLICITY

Dot notation > JOIN semantics filth

Page 56: Mysql to mongo

SUMMARY

Mongo is perfectly suited for an app like CVBeast.

Page 57: Mysql to mongo

SUMMARY

Where a relational DB forces storing object properties as relationships

Page 58: Mysql to mongo

SUMMARY

Mongo narrows this mismatch considerably

Page 59: Mysql to mongo

SUMMARY

A CV is a document...

Page 60: Mysql to mongo

SUMMARY

So a document-oriented datastore seems appropriate.

Page 61: Mysql to mongo

SUMMARY

Many object models have this tree-like structure.

Page 62: Mysql to mongo

SUMMARY

Be willing to step outside of your comfort zone

Page 63: Mysql to mongo

SUMMARY

And use Mongo when it’s practical.