Why Use Postgres?
craigkerstiens.com
craigkerstiens.com
https://www.postgresql.org/docs/9.6/static/functions-range.h...
Holy shit. Why hasn't anyone talked about it sooner? I've seen literally dozens of tables with
begin TIMESTAMP,
end TIMESTAMP,
and with handmade validation against intersection. And there is even a union operation! Seriously, my mind is blown.Rails even supports it!
http://edgeguides.rubyonrails.org/active_record_postgresql.h...
The anti ORM movement convinced only a few interested database users.
It's because of the Django docs that I've learned about a few of those awesome fields types. https://docs.djangoproject.com/en/1.11/ref/contrib/postgres/...
IMO this was because they were too dogmatic and ignored the things ORM's did better, focusing on performance that didn't matter or on issues that come up even when you don't use an ORM (n+1 in the architecture).
That said, I don't think anyone that hasn't learned SQL really don't understand their ORM either. It's one of the fundamentals that any developer should know before they ever write production code.
CREATE TABLE reservations (
room text,
during tstzrange,
EXCLUDE USING gist (room WITH =, during WITH &&)
);
You could also still have two columns and use an expression. CREATE TABLE reservations (
room text,
start timestamptz,
stop timestamptz,
EXCLUDE USING gist (room WITH =, tstzrange(start, stop, '[]') WITH &&)
);Not nearly as mature libs as Java.
create table reservation (room text, duration tstzrange);
insert into reservation (room, duration) values
('A100', '[2017-04-30, 2017-05-07]'),
('A100', '[2017-05-10, 2017-05-12]');
create view my_orm_sucks (room, start, stop) as
select room, lower(duration), upper(duration) from reservation;
Let's pretend building A caught on fire, so we have to move to building FM: select * from my_orm_sucks;
room | start | stop
------+------------------------+------------------------
A100 | 2017-04-30 00:00:00-07 | 2017-05-07 00:00:00-07
A100 | 2017-05-10 00:00:00-07 | 2017-05-12 00:00:00-07
update my_orm_sucks set room = 'FM200' where room = 'A100';
The underlying table gets updated: select * from reservation;
room | duration
-------+-----------------------------------------------------
FM200 | ["2017-04-30 00:00:00-07","2017-05-07 00:00:00-07"]
FM200 | ["2017-05-10 00:00:00-07","2017-05-12 00:00:00-07"]
Note that updates involving the start and stop columns won't work with a view like that. You can use the rules system to get around that:https://www.postgresql.org/docs/current/static/sql-createrul...
https://www.postgresql.org/docs/current/static/rules-views.h...
Or better yet, fix the driver or ORM!
It's a bit of an issue for something offering unique or novel features, because there's the risk no one will ever find them.
I'd possibly think that most people also just go "we'll use a db" and pick from mysql and postgres (probably based on which one comes to mind first for them), but don't ever think about it any more than that.
I wonder whether an official "cool things you possibly don't know about (and when/why they're useful)" page could help? Or maybe a "designing a schema/model? here a some features that might make your life better" page could help spread the word? Postgres is lucky to have Craig as an advocate, and I love reading everything he writes, but maybe someone just getting exposed to Postgres doesn't know to look at Craig's stuff? (Although, maybe Google rankings would make this page appear early enough to do a great service...)
I was talking to another dev (who's very experienced) about dbs and I said I'd always expect to go postgres because of the extra features (and intentionally tightly couple to it) and the response was "yeah but how often do you actually use them" which initially shocked me (answer was "all the time"....), but now that I think about it; it's probably a pretty common perspective...
Of course... I'd welcome more reading my blog, at the same time there are a lot of others that introduce good Postgres content to the world. This was my biggest goal in starting to curate Postgres weekly (http://www.postgresweekly.com) which focuses on Postgres for app devs. There's a ton in Postgres, which 9 years into spending way too much time with Postgres I'm still discovering each week so trying to help make a better way for others to learn was key.
Sadly the hard part about the cool things isn't the most important. Cool gets a lot of attention, but the really safe and stable things like transactional DDL, rich indexing, MVCC all that doesn't get as much love as hstore, JSONB, or HyperLogLog which is a shame cause they're really important when you're running a real business which cares about data integrity.
A hugely useful feature of postgres, that nearly no ORM/ActiveRecord library makes use of, is the RETURNING clause of INSERT statements[1] (also supported on UPDATE and DELETE statements, though those are less useful).
A write statement with a RETURNING clause returns a resultset just like SELECT, with one row per row inserted, updated, or deleted. In this way, you can request the values of columns whose data was dynamically determined by the postgres server. This is especially useful for sequence (ie: SERIAL, autoincrement) values, as well as other columns with default values (such as an insert datetime, or a column with a value based on a complex expression).
This functionality is amazing, yet is so underused. Try to do a multi-row insert statement with MySQL with an auto-increment primary key, and know which IDs were assigned to your rows. You can't, because there is no guarantee your auto-increment values will be sequential.
Example query, which will return the auto-increment sequence id and default insertion timestamp of the two inserted rows:
INSERT INTO members (name) VALUES ('Foo'), ('Bar') RETURNING id, created_at;
[1] https://www.postgresql.org/docs/current/static/sql-insert.ht...And the end of the day, they ended up selecting all the start and end dates and then building their own interval tree ( https://en.wikipedia.org/wiki/Interval_tree ) and doing overlap detection themselves.
If they were using a database with good stored procedure support and had the skills to write the stored procedure or function in the database, they might then fight with writing the overlap detection there... but they likely found it a profoundly unpleasant experience.
And then here's PostgreSQL. It has it native. Hours, days, weeks of time spent writing, testing, debugging and otherwise fighting with this problem now suddenly become something along the lines of "SELECT isempty(daterange('2017-04-30', '2017-05-07')) FROM reservations" or something to that effect.
It represents a significant time savings when you need it for things that are more interesting than reimplementing data structures that aren't in the standard libraries.
create table reservation1 (duration tstzrange);
select * from reservation1 where duration && '[2017-04-30, 2017-05-07]';
In a database without range types, it would look like this: create table reservation2 (start timestamptz, stop timestamptz, check (start <= stop));
select * from reservation2 where '2017-04-30' <= stop and start <= '2017-05-07';
Personally, I don't think range types by themselves are anything special. However, combined with indexes and exclusion constraints, they're really great: create table reservation1 (duration tsrange, exclude using gist (duration with &&));
insert into reservation1 values ('[2017-04-30, 2017-05-07]'); -- ok
insert into reservation1 values ('[2017-05-10, 2017-05-12]'); -- ok
insert into reservation1 values ('[2017-05-05, 2017-05-08]'); -- error!
Here's the difference indexes made when retrieving all the scheduling conflicts with a fixed interval (500k rows): No index (start, stop) 123ms
Btree index (start, stop) 29ms
GIST index (duration) 0.2ms
Quite a difference!Hopefully the partitioning thing is soon fixed 'properly'.
I would appreciate a really long text that would in a convincing manner explain why Postgres Is so awesome.
I work in the industry, and all I see are Oracle and Sybase everywhere. The experts are zealots also, not even having heard of Postgres. Not willing to believe a word I'm saying about Postgres.
I am already convinced of course, but the industry is not. Not finance, not trading, not telecom.
That is, although those two products may indeed have some merit, that is not why they are chosen.
The best example of this is Salesforce, which has their own proprietary SQL-like query language that's clearly just a crappy front end to generate raw SQL to feed their Oracle DB's. Without Oracle's per-tenant limit this would be far too risky because of idiots making bad queries.
An better solution these days is to put each tenant in a Postgres container and let the OS control resource limits for them, but this wasn't an option until recently.
Killing connections can be done in postgresql too. The reason for sf to be on oracle is probably history.
A few things I've found great in Oracle that aren't (AFAIK) available in PG:
- Straight better/more reliable performance on average
- More advanced parallel queries (obviously this is changing in PG right now)
- Flashback queries
- Better materialized views
- Plan stability (maintains predictable query performance, rather than the nasty jumps you sometimes see when plans change)
- Better clustering story (RAC is super expensive but pretty good)It was actually good and very easy to activate. If you did activate it though you could expect a sizable extra invoice after next audit.
This unfortunately has become very common.
The first result is a blank copy of a license agreement that they presumably forgot was on their website.
You aren't allow to publish benchmark results, a condition that is both upsetting and not at all unique as commercial databases go http://m.sqlmag.com/sql-server/devils-dewitt-clause
It is awesome in a way but had some awful bugs (lost hours to installer bugs) and was topped up with dark patterns IMO (expensive features would be one click away)
Edit: and can we stop pretending that OS X is better? It is different. Some people like that. Other has just as legitimate reasons to stay away.
I spent 3 years on a Mac and went from really enthusiastic to really disappointed. I still defend others right to prefer it though and hope you'll defend my choice as well.
Having been exposed to Linux on the desktop for more than a couple of decades, in addition to using OS X since 2003, my subjective opinion is that it's not only far more mature, but better in almost every conceivable way.
That goes for casual users to developers. The ecosystem from Apple is maybe not perfect, but I still dare to use the word fantastic.
But we are not supposed to argue over such things here.
I'm just asking that Mac people respect that I and others way prefer other OS-es like Linux, BSD or even Windows.
[0]: like 1.) not having consistent shortcuts for moving using the keyboard 2.) With two monitors the menu bar will be very far away when you work on the other monitor 3.) One Chrome window would block the other, preventing me from finding the instructions on the wiki while having a file select box open in another.
Etc etc. This is before I start my rant about things more unrelated to their OS implementation like a) putting fn in the bottom left corner b) not giving me any chance to fix it c) the fact that many programs I want to use was either unavailable or looked horrible.
Golden Gate, RAC, Management Tools, stable plans, decent parallelism, decent partitioning, some columnar stuff - that's not just marketing fluff.
Oracle's politics / sales tactics, and cost are one large argument against, being able to influence feature development / add features yourself another, against Oracle, that I've seen driving companies - including big financial ones - away from oracle over time. Often that's not starting with the business critical stuff, but with some smaller project, and then grows over time.
There's some things (better replication out of the box , higher performance).
> but not much discussion on how PG will come to parity
That's because this subthread started with "No one ever chooses Oracle or Sybase on technical merits." - neither Postgres' strengths and needed/planned improvements are relevant to refute that position.
> on how PG will come to parity and how we'll know when it's finally good enough to use.
Just because Oracle has some features that postgres doesn't match doesn't mean it's not good enough. There's a lot of features where postgres is further along than Oracle, too. For a good number of OLTPish workloads postgres is faster.
We're talking about large and complex products here - it's seldomly the case that one project/product is going to be better than all others in all respects. Postgres has been good enough to use for a long time.
If you're interested in which areas postgres needs to improve, I'm happy to talk about that too.
If you're fighting the attitude that the only viable option is one that costs a ton of money instead of a decision based on technical merit, additional facts about Postgres won't help.
Sometimes the decision gets made on a golf course and not after reading very long texts.
This is why I swore to only write software at software companies some years ago. For other industries software is just another expense like buildings or supplies. The people buying it have no idea what they're looking at so they buy the shiny thing that everyone else is buying.
When I worked in other sectors I regularly saw executives attempt to assemble software as if it was a large building. Materials were gathered, agreements were made to purchase or rent heavy equipment, and the whole project was planned out with exacting detail. When all the permits and contracts were in place construction would begin. This was to be done in a measured amount of code using the chosen architecture, and delivered complete on a certain date. Any deviations were seen as workarounds for not following the original plans, and overruns the result of incompetence. The whole thing was just a shitshow of incompetence at the higher levels.
Demanding and exercising the use of a throat to choke is a massive, massive part of how at least American business works due to prevailing leadership styles as well. It also shows how they tend to view their workers as well. "Blameless culture" is something that is a tiny, tiny minority that only seems to have worked out well among socialist-ish boutique software companies and until we start seeing companies that practice traditional Taylorist and authoritarian leader worship cultures fail very disproportionately, nothing will fundamentally change.
I'm familiar with a number of very large deals done basically between C-level to C-level where the scope of IT projects has nothing to do with technologies but entire about cost savings - literally "I will save you $n MM / yr in opex so you can get your bonuses" and other vendors get shut out. Sometimes these deals work out, other times they don't and the executive is basically ousted. Companies with bad politics and enormous cronyism may have worked fine for decades, but they just may not be doing as well anymore unless you're on Wall Street and you make so much money it doesn't matter how it's done.
Software is not the end-goal itself. The point is not to make (or use) amazingly elegant software. The point is to make money.
If a supplier says "I will provide the same service as you are currently getting and cost you $X less" then that's a no-brainer regardless of what service they're providing. It's got nothing to do with technology, and technology doesn't change the nature of that decision.
"Having a throat to choke" is also a matter of insurance. You can't insure against your own incompetence, but you can sue a supplier for not fulfilling the terms of their contract. Executives would much rather negotiate what they think is a tough contract with a supplier than manage a complex project themselves. To that mindset, the removal of risk (because if anything goes wrong they can sue the supplier) is a huge bonus.
It's a totally different mindset from those of us who actually make things.
The company for the longest time wouldn't even touch basic firewall rules without having the firewall contractor implement it.
I think is the better point or rewording of your point.
https://www.itnews.com.au/news/queenslands-ibm-ban-lives-on-...
Many also think looking up issues on stackoverflow, google or blogs as unreliable. Then there are times when issues might be specific to installs or data, in which case sharing the logs/sample data (even masked ones) can be risky. They feel comfortable sharing logs/masked data with for example Oracle because they believe it to be safe and locked under Oracle's security guidelines.
The 2nd refrain I hear is - security. In case of a major security issue being revealed, there is a general sense that FOSS will be slower to react in releasing a "stable" patch. Comparatively paid software take it as a reputation risk and work towards quickly releasing a "stable" patch.
If people have to use FOSS, then they try and search for the paid support flavor. Recently we were looking at MQ software. When we zeroed in on RabbitMQ we were asked to deploy only the paid Pivotal version and not the free version because "support".
Sure, these things might not be completely true but for many higher ups paying for something somehow makes them sleep better at night than a "free" alternative.
> Written for longevity
OSS is much better at longevity than proprietary. Even if the authors all die without will, it is possible to fix the little bugs that prevent you from using the software on [NewTechnologyHere]. I've done it countless times with Java software; If anything OSS is the guarantee that you own your future and that the system will exist in the legacy.
> Use paid flavor
It's good, but what's better is joining the golf club of a principal maintainer. He's key in paying him to fix the issue you're having quickly and merging upstream.
Long, long ago when I worked at Nortel (a now defunct, but then huge telecommunications company), they used to pay millions of dollars a year to Cygnus to support a particular embedded version of GCC. This, despite the fact that Nortel had more than 10k programmers on staff including a compiler team!
I think the real reason these support contracts exist is because companies (even large ones) don't want to dilute their focus maintaining projects that are peripheral to their core business. It's not so much a technical problem, or a money problem -- it's a management problem. They can't scale out to handle every little thing.
I think OSS is a red herring in this conversation. Most companies just don't care about that. They don't want to support it themselves (even if they are big enough to do so), and they need to have confidence in the company that provides the support. Build that company (hint: you need to be sales heavy!) and you could sell Postgresql just as easily as any other database. Of course breaking into an entrenched area in Enterprise software is always going to be difficult, so I'm not sure how successful you would be with this particular product, but you get my point, I think.
As hindsightbias puts it they want solutions and 24*7 support.
Specifically, I've seen pg take a query that looks like this:
select ... from a join b join c join (select ...) d
where a has millions of rows and is an equijoin with d where d has 10 rows, and it decides to materialize a x b x c, only joining in d at the last step. But do it like this: select ... from (select ...) d join a join b join c
and it does the right thing! And analyze gets it right (i.e. the plan for the reordered joins is recognized as better) - never mind genetic optimization, it's lacking analytic optimization.With the lack of hints, almost the only tool you have to control query plans effectively in postgres is parenthesized joins. Since it's more liable to rewrite the query, the language ends up being less imperative, and thus less predictable. And I like predictability in production.
SQL-level feature set is no comparison of course, pg wins easily.
It is interesting to see how postgresql will often choose hashmap scan, even with very up to date statistics and much better paths available.
SQLServer's planner does an amazing job of digging right into joins/sub-selects to constrain preliminary results for joins.
It's a very hard job and MS and Oracle obviously have had some of the best people on the world paid well to work on this.
I'd also suggest disabling nest_loop_entirely if you are having problems with bad cardinality estimates resulting in nestloop plans that run 100 times when the planner estimated once.
I was a Sybase point person for years at a fortune 50 medical devices enterprise company (we had revenues of well over $1B annually on devices running Sybase dbs). There were dozens of bugs/issues I found that I pushed up the chain to an engineer and had special patches turned around within 48 hours, sometimes even hours.
Before I left that job I started playing around with Rails and mentioned MySQL and Postgres for a potential greenfield project. I was told it would be fine for internal use but no way, no how were they going to deploy any software without that kind of parachute based on economic leverage.
Making software work at scale without that economic leverage could never work in theory. It only works in practice.
Oh, and those who did it were above oracle in terms of data size making it rational decision too. The calculation is still different for majority of companies.
Often enough you'll even get similar turn-around times from the community, if you can't (or don't want to) afford such a support contract.
Let me rather call it, The Real World.
I work in a Fortune 500 company, a consultancy of 400.000 people, on projects for other Fortune 500 companies.
My experience is from the real world.
In cloud/managed space, Postgres is also hit and miss - still no good cross-region option and frankly other than AWS RDS not many other managed Postgres services.
So, MySQL rules the cloud/managed databases, and oracle/sybase/mssql rule on prem.
"This is a Beta release of Cloud SQL for PostgreSQL. This product might be changed in backward-incompatible ways and is not subject to any SLA or deprecation policy."
Google recently added beta version of Postgres to Cloud SQL as well (https://cloud.google.com/sql/docs/postgres/). Of course, AWS RDS and Heroku have been on the market for some time.
I'd claim managed Postgres market is in a pretty good shape.
Netflix, eBay, Apple, Sony (for PSN), Spotify are all Datastax customers paying for the commercial version of Cassandra.
Facebook, Foursquare, eHarmony, Buzzfeed, LinkedIn are listed as paying customers of MongoDB.
Postgres is in the same range of relational enterise SQL database engines. Postgres offers even Oracle PL/SQL compatible syntax, so you can think of Postgres as the Linux of relational databases. (Linux is a clone of Unix). If you need advanced SQL syntax, XML support, complex triggers, inlined procedural code, GIS, etc look no further than this and choose Postgres. If you just want to hit your DB with thousends of connections from your web application frameworks and public APIs or think of easy clustering, it might be a good idea to add a caching layer in-front like memcached/redis or read on... (as the forking model doesn't scale that good)
And then there is a unique database-software with a common SQL dialect that supports dozends of database engines. It's called MySQL and it supports plugin-engines like InnoDB (default, true web scale, very fast), ISAM (old 1980s style features, very fast), etc. MySQL can handle many concurrent connections and InnoDB is really good, that's why it's a very good fit for web apps, using basic SQL features and used by Google, Twitter, Facebook, etc as a main production database.
And there are NoSQL databases that have different kinds of features like MongoDB/RethinkDB, Lucene (Solr/ElasticSearch), Hadoop (HBase, etc), Cassandra, etc. - they have often just basic SQL-like query language or non at all, but a custom API to interact with the datastore. Those domain specific solutions are often very fast for certain use cases. Some have limited index support, limited join support, transactions, etc. so the it really depends. E.g. for JSON datastore and full text search, those are ideal solutions.
We would need a database guide that highlights the common open source database engines. And provide a transition guide and compatibility matrix compared to legacy binary blob database engines - the real competitors to open source. People in the open source communities are often fishing in other communities and try to convert them - instead look no further than your corporate colleagues and enterprise fellows and try to convert them away from their rusty databases.
The real costs are:
1. Need for a third party connection pooler (built-in in many client libraries like JDBC, ActiveRecord or Sequel). Some poolers like pgboucner lack support for prepared statements.
2. Memory usage can become an issue, especially if you have tens of thousands of stored procedures since stored procedures are compiled and cached per connection. Also working memory for sorting is per connection which means PostgeSQL will use more memory than MySQL on some workloads.
3. Having to recompile all stored procedures on first use after reconnecting to the database can be an issue.
being able to have a field like:
ingredients VARCHAR[]
and index like: USING GIN (ingredients)
and using an operator like @> SELECT * FROM table WHERE ingredients @> ARRAY['mushrooms', 'sour cream']
gives you such amazing flexibility and speed, it's not even funny.also, while I was sad to not see PLV8 up there with PostGIS (an amazing extension, btw), I was still happy to see it mentioned with such gusto.
SELECT * FROM recipes r
INNER JOIN ingredients i ON (r.id = i.recipe_id)
WHERE i.ingredient IN ('mushrooms', 'sour cream')
load up some data and run explain analyze on both schemas/queries.I think WordPress and php guys default to MySQL.
I think python and Django guys end up defaulting to Postgres.
Rails and node.js I am less sure what the default is, maybe mongodb?
I don't think either camp has really changed since Oracle came along. A lot of momentum in different stacks.
For Node, well, it varies, but at least once upon a time, people used to talk about the "MEAN" stack (MongoDB, Express, Angular, Node) - MongoDB and Node are certainly often used together.
[1] Not MySQL - edited as per the below correction.
Oracle's control over MySQL and the shift towards Open Core over FOSS fundamentals has pushed some companies to use the compatible MariaDB option over it. Most Linux distros use MariaDB by default now, meaning more LAMP stacks by default having MariaDB over Oracle's MySQL.
I'm certainly not saying MariaDB is taking over MySQL, just the trend I've seen being a RHEL Sys Admin.
I have stored procedures doing a bunch of stuff and returning a nicely formatted JSON object that makes the job of the application code a lot easier.
One thing I dislike is that the friction for initial development and prototyping is a little too high.
You have to have scripts lying around to re-create the functions when you change it during dev.
And logging/debugging/etc is harder and not as flexible.
# Find a row by JSON property value
select * from person where details->>'name' ilike '%james%'
# check for property existence
select * from person where details ? 'is_hidden'
# Override a single property in a JSON field -
update person set details = details || '{"phone":"911"}'
# Alt increment existing value
update person set details = jsonb_set(details, '{views}', (details->'views')+1)
More examples at https://www.postgresql.org/docs/current/static/functions-jso...I used to use Mongo along side the PG for the JSON store but now am back all on PG with this JSONB type.
Now the product's data model is mostly settled I am flipping over to regular fields, array types, and higher normal forms.
Being able to do all this without changing DB backend has been a real boon, far less time bogged down in ops = far more time to create customer value.
The json support is amazing. It's really incredible.
I considered MS SQL for Linux but the server alone required 3GB RAM...
But because this is about someone coming from a more traditional RDBMS (like oracle, sql server, sybase) it will note that some or most of the features of PG are not different from something like them.
Also, PG was from the start more focused in be robust, instead of MySql that was focused in be fast (at the cost of being robust). PG is a better fit for more traditional workloads from years now.
And the careful, well-thought, solid development, feature implementation and release discipline is clearly very professional, to match the ones from commercial vendors.
PG is not just good for startups and enthusiasts, but solid enough to be recommended to most companies with total confidence.
On the other hand what you say is true, ES is much more flexible in what it can offer in full text search.
Postgres is an amazing piece of software.
suggestion: under 'Much More' it would be useful to link to articles or docs about each of the features listed.
Unfortunately, having something like v8 as a postgres build dependency would be pretty drastic increase in build requirements.
A number of distributions of postres (debian/ubuntu packages (all versions http://apt.postgresql.org/), rhel based (https://yum.postgresql.org/) provide it in an easy manner. I'm not sure there's something as convenient for OSX and windows however :(
[ pg installs I work with are invariably running on linux, so all good. ]
ps: I don't mind the downvoting. I am truly looking for answers.
However, by constraints I was more talking about things like "these properties need to be unique", "this column here must reference that column over there", "this column's values must be in this set" and so on.
I know I could enforce these things in the application layer, but I don't think that's feasible.
Edit: Typo
Whether you enforce password complexity in the database is a question of where your team is more comfortable working, and what the business requirements are.
You can enforce complex constrains like this in `>3.0`:
db.createCollection( "contacts",
{ validator: { $or:
[
{ phone: { $type: "string" } },
{ email: { $regex: /@mongodb\.com$/ } },
{ status: { $in: [ "Unknown", "Incomplete" ] } }
]
}
} )
While still not having to define the rest of the schema that you don't want too. It feels more flexible.I couldn't make a universal statement about where the constraints you're talking about should go without knowing the business rules for the application.
Primarily, security.
Good question! Why not have all the logic in the database?
The answer is, you can actually do that. And it’s popular enough that someone founded a company on that concept, although they didn’t use Postgres, but their own self-built database.
You might have heard of it: https://firebase.google.com/ (They were acquired later, and are now Google’s top database offering).
At least two OSS backend stacks, PostgREST and PostGraphQL, are built on exactly this idea. And there's at least one commercial stack with the same idea: SlashDB.
(in general, I'm not a fan of Object-Foo-Mapping, but then I've used dynamic/runtime typed languages on and off since the 80s)
The migrations don't drive your schema, the schema drives the migrations. Proper tools don't make you have a bunch of .SQL files that organise your database.
pg_dump -s your_db | less
Or you can explore it using `psql`: $ psql your_db
List schemas: your_db=# \dn
List tables in a schema: your_db=# \dt public.
Show table detailed info (constraints, indexes, comments, etc.): your_db=# \dt+ your_table
List functions: your_db=# \df
Or you can install pgAdmin and browse through the entire database--tables, constraints, indexes, the whole shebang--in a single screen. At no point are the migrations burying the schema. That's just a fundamental misunderstanding of how to work with databases.No one is making you enforce schemas with PostgreSQL if you work this way.
As for enforcements - there are things that are _impossible_ to enforce at an application level for atomicity reasons - for example - if you have a `users` table and you can't have duplicate email addresses - you'd need the operation "check if a user with the said email exists, if it does - return it, if it doesn't create it and return it" - PostgreSQL can do this easily, which prevents duplicate entries - Mongo - not so easily (see the "two phase commit" docs for how to simulate transactions).
Can't you easily do it with upsert in Mongo?
But, if you think of your database as a single source of truth, then I almost can't imagine any reason to use mongo[1]. Without ACID transactions it is your problem to enforce all those pesky constraints across your whole codebase and data storage. And that work is HARD.
For instance. I once had to implement a simple scheduling app. Basically, if worker A was scheduled to work from 2017-04-30T18:00:00 to 2017-04-30T18:30:00, then there can't be any overlapping schedule item for said worker. I guess you can do something like a two-phase commit with mongo, but I used a tsrange[1] and an exclusion constraint, and got everything almost for free.
[1] Well, AFAIK mongo has better sharding. For now :)
[2] https://www.postgresql.org/docs/9.6/static/rangetypes.html
[3] https://www.postgresql.org/docs/9.0/static/ddl-constraints.h...
---
A schema-less storage design have some valid uses cases. But even them leak a undeniable truth:
All schema-less design are already a enforced schema, but more general.
Even a KV store is a enforced schema. You have key, and values, and specific operations on them.
Eventually, you will note that that schema-"less" design is too constrained / liberal. For the same reason you note that use all the time hash tables is not as good. You need arrays, and objects, and list, and records, etc.
And you noted that some operations start to repeat themselves. Will be nice if that become abstracted? Right?
And you will noted later that provide reliable results is very hard, specially if things are out-of-order, multi-thread, multi-process, etc.. Will be nice that that become abstracted, right?
And then you can do all that yourself, in your language of choice. And is fine!
But later, you will need to use another language. Now, you need to repeat all that effort AGAIN. Will be nice if you use something like all that about micro-services and stuff, and put the hard-part isolated and caring about that, and you can freely mix-match tech as you see fit?
But then, you do all this, and you MISS THE DAMM SIMPLICITY OF A KV STORE!. How nice will be if exist a model, let's call it relational, that not only can model a KV store, but much MUCH MUCH more!
TADA! You have reinvented a RDBMS!
The strongest reason is that the database will complain loudly if you want to make a change that breaks existing constraints. An application, no matter how simple, will probably change, and you don't want to leave data out there that is unreadable and that will break your application's expectations. The schema minimizes the chances of garbage historical data that have been, in my experience the plague of NoSQL-backed apps. Often you find people that end up writing ad hoc constraint checkers, creating a poor imitation of what a database that understands schemas does well.
Another big reason is that there's rarely just one application, and the applications could (and very often should) be written in different languages. A schema at that point becomes a service which just happens to not use Json or Thrift, but a far more complicated, sturdier one. You could still argue that databases are too complicated to expose very widely, but I'd much rather have all my data sitting in the very schema-heavy redshift to do reporting than to rely on application logic, or use most business insight tools out there.
Also, let's not forget that schemas let databases do a lot of complex operations rather cheaply, because they can have very optimized code of very specific shapes next to the data. In the cases where 'first, I will take 50K rows out of the db and into my application' is just not acceptable, you have to let the DB do the work. In those cases, the interface to use a windowing function in a SQL database is IMO far more convenient than having to go into the classic remote map reduce function in erlang.
I think there were plenty of gains from the NoSQL movement, especially as far as to start writing database where high availability and horizontally scalable loads are concerned. But outside of those realms, where few companies really are, I would not recommend a schemaless database today.
Just to elaborate a little on your third paragraph, this is incredibly important as an app matures. You might start out thinking you're only ever going to have one interface to a datastore, but the reality is that you always have at least two. Someone has the ability to go directly to the store itself and make changes. That's life. Someone at some point in the lifetime of your app or company is going to go in and have to fix things by hand. If you have no schema and no constraints in the datastore itself, the odds of an error make things worse are far, far greater.
We all know that's bad practice, but we all also know that sometimes you just have to do it for some reason. We also know that there will be times when someone is testing something on what they think is the local testing db but are actually connected to prod, and they do something experimental, and it screws things up. That's also a terrible thing to let happen, but we all know that it does.
The second thing I'd like to point out that, much like sending email, any sufficiently useful application will, at some point, provide an API. And you're going to have to re-implement the backend validation again for that.
So you know from the outset that if you are working on something you expect to be successful, you're going to have 3 access points. You're going to have to do the same work 3 times in 3 different places, unless you just decide to take the risk and use a db that doesn't have schema or constraints--which is a big risk. Doesn't make sense to me.
Finally, I'd like to add to this good post that it's pretty easy to work in either direction with many ORMs. If you're comfortable with DBs, you can write out your migration scripts and use the ORM to generate models from it. If you prefer to work with an ORM, you can write the model and manage the migrations in the ORM. Either way, there's really not that much overhead compared to what you gain in safety and security and DRY.
I'm not a DRY nazi, and when I'm prototyping, I'll repeat code anywhere I suspect a later iteration to diverge from the other instances of that code, and then refactor when I get closer to production. But when you're talking about database structure, I don't see how that can diverge, so it makes sense to me that you should never repeat yourself there. That's just asking for trouble.
Do it once in the database, and do it right. Then all you have to do is trap database errors in your backend code and validate on the front end. That will be different for every interface, but it's a lot simpler and cleaner and safer than enforcing schemata and constraints in every codebase that accesses the data store.