A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus...

115
A call for sanity in NoSQL Nathan Marz @nathanmarz 1

Transcript of A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus...

Page 1: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

A call for sanity in NoSQL

Nathan Marz @nathanmarz �1

Page 2: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

“Doofus programmer”

Page 3: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

You broke the build!

Page 4: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Where are the tests?

Page 5: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

The site is down!

Page 6: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

DELETE FROM users...

Page 7: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Oops, I forgot the WHERE

clause!

Page 8: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

=

Page 9: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

=

Page 10: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...
Page 11: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...
Page 12: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

No problem...

Page 13: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...
Page 14: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Mistakes are guaranteed

Page 15: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Create Read Update Delete

Page 16: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Mutable database

Guaranteed corruption=

Page 17: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Insane

Page 18: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Schemaless databases

Page 19: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Insane

Page 20: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Avoiding complexity

Page 21: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...
Page 22: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

counter++

Page 23: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Insane

Page 24: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Denormalization

Page 25: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

ID Name Location ID

1 Sally 3

2 George 1

3 Bob 3

Location ID City State Population

1 New York NY 8.2M

2 San Diego CA 1.3M

3 Chicago IL 2.7M

Normalized schema

Page 26: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Join is too expensive, so denormalize...

Page 27: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

ID Name Location ID City State

1 Sally 3 Chicago IL

2 George 1 New York NY

3 Bob 3 Chicago IL

Location ID City State Population

1 New York NY 8.2M

2 San Diego CA 1.3M

3 Chicago IL 2.7M

Denormalized schema

Page 28: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Insane

Page 29: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

What is the source of the insanity?

Page 30: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Code is deterministic. I understand logic.

Therefore, I can write correct code.

Programming fallacy

Page 31: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Your code is wrong

Page 32: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Your code

Dependency 1

Dependency 2

Dependency 3

Page 33: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Dependency 1

Dependency 4

Dependency 5

Page 34: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Dependency 4

Dependency 6

Dependency 9

Dependency 7

Dependency 8

Page 35: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Dependency 3,000,000

Hardware

Page 36: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Electronics

Page 37: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Chemistry

Page 38: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Atomic physics

Page 39: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Quantum mechanics

Page 40: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

I think I can safely say that nobody understands

quantum mechanics.

Richard Feynman

Page 41: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Your code is wrong

Page 42: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Your code

...

Page 43: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Infinite regress

Page 44: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

All the software you’ve used has had bugs in it

Page 45: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Including the software you’ve written

Page 46: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...
Page 47: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...
Page 48: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

- Mutability - Schemaless databases - Eventual consistency / read-repair - Denormalization

Insanity

Page 49: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Person Location

Sally New York

Bob Chicago

Mutability

Page 50: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Person Location

Sally London

Bob Chicago

Mutability

Page 51: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Person Location Time

Sally New York 1318358351

Bob Chicago 1327928370

Immutability

Page 52: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Person Location Time

Sally New York 1318358351

Bob Chicago 1327928370

Sally London 1338273801

Immutability

Page 53: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

All data

Precomputed batch view

Query

Precomputed realtime view

New data stream

Lambda Architecture

Page 54: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Relational database

Page 55: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

NewSQL

Page 56: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

All data problems?

Page 57: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

What does a data system do?

Page 58: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Retrieve data that you previously stored?

GetPut

Page 59: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Counterexamples

Store location information on people

Where does Sally live?

What are the most populous locations?

How many people live in a particular location?

Page 60: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Counterexamples

Store pageview information

How many unique visitors over time?

How many pageviews on September 2nd?

Page 61: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Counterexamples

Store transaction history for bank account

How much money do people spend on housing?

How much money does George have?

Page 62: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

What does a data system do?

Query = Function(All data)

Page 63: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Example query

Total number of pageviews to a URL over a range of time

Page 64: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Example query

Implementation

Page 65: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

On-the-fly computation

All data

Query

Page 66: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Precomputation

All data

Precomputed view Query

Page 67: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Precomputed view

Example query

All data

Pageview

Pageview

Pageview

Pageview

Pageview

Query 2930

Page 68: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Precomputation

All data

Precomputed view Query

(Immutable)

Page 69: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Precomputation

All data

Precomputed view Query

Function Function

Page 70: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Computing views

All data

Precomputed viewFunction

Page 71: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Function that takes in all data as input

Page 72: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Batch processing

Page 73: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

MapReduce

Page 74: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

MapReduce is a framework for computing arbitrary functions on

arbitrary data

Page 75: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

All

data

Batch view #1

Batch view #2

MapReduce workflow

MapReduce workflow

MapReduce precomputation

Page 76: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

All data

Precomputed view Query

Page 77: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

All data

Precomputed view Query

Normalized Denormalized

Page 78: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Human fault-tolerant

Page 79: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Not quite...• A batch workflow is too slow• Views are out of date

Absorbed into batch views Not absorbed

Now

Time

Just a few hours of data!

Page 80: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Precomputation

All data

Precomputed batch view

Query

Precomputed realtime view

New data stream

Compute parallel realtime views

Page 81: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

NoSQL databases

New data stream

Realtime view #1

Realtime view #2

Stream processor

Page 82: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Precomputation

All data

Precomputed batch view

Query

Precomputed realtime view

New data stream

Most complex part of system

Page 83: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Precomputation

All data

Precomputed batch view

Query

Precomputed realtime view

New data stream

But only represents few hours of data

Page 84: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Precomputation

All data

Precomputed batch view

Query

Precomputed realtime view

New data stream

So can be kept small

Page 85: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Precomputation

All data

Precomputed batch view

Query

Precomputed realtime view

New data stream

If anything goes wrong, auto-corrects

Page 86: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Precomputation

All data

Precomputed batch view

Query

Precomputed realtime view

New data stream

“Complexity isolation”

Page 87: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Precomputation

All data

Precomputed batch view

Query

Precomputed realtime view

New data stream

No random writes needed

Page 88: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

All data

Precomputed batch view

Query

Precomputed realtime view

New data stream

“Lambda Architecture”

Page 89: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Applying the Lambda Architecture

Page 90: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Unique visitors over a range of hours

ABCA

BCDE

CDE

1 2 3 4Hours

Pageviews

Page 91: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

ABCA

BCDE

CDE

1 2 3 4Hours

PageviewsA = BB = D

Equivs

Unique visitors over a range of hours

Page 92: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

What should view look like?

Page 93: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Attempt #11-1 3

Count

1-2 61-3 62-2 42-3 53-3 1

Hour rangeURL

foo.com/blog

1-1 31-2 61-3 62-2 42-3 53-3 1

bar.com/foo

Page 94: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Attempt #2

1 3Count

2 63 64 85 56 1

HourURL

foo.com/blog

1 12 113 234 85 96 0

bar.com/foo

Page 95: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Attempt #3

1 A, B, CVisitors

2 A3 D, E4 A5 B, C, D6 F, G

HourURL

foo.com/blog

1 A2 B, C3 A, C4 D5 A, E6 A

bar.com/foo

Page 96: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Attempt #4

1 <HLL>HyperLogLog set

2 <HLL>3 <HLL>4 <HLL>5 <HLL>6 <HLL>

HourURL

foo.com/blog

1 <HLL>2 <HLL>3 <HLL>4 <HLL>5 <HLL>6 <HLL>

bar.com/foo

Page 97: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Final attempt1 <HLL>

HyperLogLog set

2 <HLL>3 <HLL>4 <HLL>5 <HLL>6 <HLL>

HourURL

foo.com/blog

1 <HLL>2 <HLL>3 <HLL>4 <HLL>5 <HLL>6 <HLL>

bar.com/foo

1 <HLL>HyperLogLog set

2 <HLL>3 <HLL>4 <HLL>5 <HLL>6 <HLL>

MonthURL

foo.com/blog

1 <HLL>2 <HLL>3 <HLL>4 <HLL>5 <HLL>6 <HLL>

bar.com/foo

1 <HLL>HyperLogLog set

2 <HLL>3 <HLL>4 <HLL>5 <HLL>6 <HLL>

WeekURL

foo.com/blog

1 <HLL>2 <HLL>3 <HLL>4 <HLL>5 <HLL>6 <HLL>

bar.com/foo

Page 98: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Batch workflow

All data

Normalize pageview URLs

Equiv connected-component labeling

Normalize pageview userids

Aggregate HyperLogLog sets

per bucket

Index into batch view

Page 99: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Equiv graph

1 3

4

5

11

2

7

6

9

Page 100: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Equiv graph

1 3

4

5

11

2

7

6

9

Person A Person B

Page 101: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Equiv graph1 -> A 2 -> A 3 -> A 4 -> A 5 -> A 11 -> A 6 -> B 7 -> B 9 -> B

Page 102: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Batch workflow

All data

Normalize pageview URLs

Equiv connected-component labeling

Normalize pageview userids

Aggregate HyperLogLog sets

per bucket

Index into batch view

Page 103: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Realtime workflow

The equiv problem

Page 104: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

The equiv problem

1 <HLL>HyperLogLog set

2 <HLL>3 <HLL>4 <HLL>5 <HLL>6 <HLL>

HourURL

foo.com/blog

1 <HLL>2 <HLL>3 <HLL>4 <HLL>5 <HLL>6 <HLL>

bar.com/foo

Page 105: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

The equiv problem

1 A, B, CVisitors

2 A3 D, E4 A5 B, C, D6 F, G

HourURL

foo.com/blog

1 A2 B, C3 A, C4 D5 A, E6 A

bar.com/foo

Page 106: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Solving the equiv problem

All data Equiv connected-component labeling

Index into batch view ofuserid -> normalized userid

Batch

Page 107: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Realtime workflow

Batch

All data Equiv connected-component labeling

Index into batch view ofuserid -> normalized userid

Pageviews stream Normalize userid Aggregate realtime HyperLogLog buckets

Realtime view

Page 108: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Schema

Page 109: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Schema

Page 110: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Schema

Page 111: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Schema

Page 112: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Schema

Page 113: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Schema

Page 114: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Conclusions from example- Avoids every single insane complexity I talked about - Powerful to be able to extract more out of a piece of data the longer you have it - Eventual accuracy is a super useful technique - Schemas can be useful and non-painful - A Lambda Architecture is fundamentally easy to extend with new views/queries

Page 115: A call for sanity in NoSQL...A call for sanity in NoSQL Nathan Marz @nathanmarz 1 “Doofus programmer” ...

Thank you