Download pdf - Mysql to mongo

Transcript
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.