Towards Multiverse Databases
blog.acolyer.org
blog.acolyer.org
It affects performance too -- SQL wants storage locality by table, but applications often want locality by user.
App-level permission / roles is something that everyone runs into with a DB-backed app of a certain size, and it has always felt to me like better hierarchy design could help -- not just foreign keys but 'settings table is under users table', you have to query it via users.
This problem gets substantially worse in geographically distributed databases, like Spanner or CockroachDB, where joining tables whose data is stored in different localities can incur a significant latency penalty (in the hundreds of milliseconds).
They both offer an interesting solution to the problem called interleaved tables. CockroachDB docs on the subject are here [0], and Spanner's docs are here [1].
Interleaved tables don't fix the fact that SQL will hand you back a flat table when you have hierarchical data, but they do fix the spatial locality problem. Here's an example, from the CockroachDB docs, of how users and their order data can be interleaved, exactly the way it sounds like you've wanted:
/customers/1
/customers/1/orders/1000
/customers/1/orders/1002
/customers/2
/customers/2/orders/1001
/customers/2/orders/1003
[0]: https://www.cockroachlabs.com/docs/stable/interleave-in-pare...[1]: https://cloud.google.com/spanner/docs/schema-and-data-model#...
Can you expand on this? I'm not sure I follow.
The only dataset that I have worked with where SQL limitations hit hard and fast was a 3D fMRI timeseries dataset, the type of data which isn't meant to be queried using SQL in the first place. Sure there's also certain graph-based datasets which you wouldn't want to use SQL but this is by far the exception and not the rule. You'd be surprised how many datasets can easily be ETL'ed and stored relationally, and even nested tree structures are generally nothing a few SQL views can't fix.
As for your "affects performance" claim - this has been made efficient for DBs like Redshift with compound/interleaved SORTKEYs and all/key DISTKEYs. And other modern warehouses like BigQuery, Snowflake, etc have their own solutions.
I think SQL is just hierarchical enough, not unlike the porridge in the Goldilocks fairy tale.
https://cloud.google.com/spanner/docs/schema-and-data-model
https://www.cockroachlabs.com/docs/stable/interleave-in-pare...
suddenly I have to store all items in a single DB row and read the whole thing to access any of them, giving me a new source of IO inefficiency
what if the target table is keyed by date and I'm selecting a small subset? JSONB will still force the DB to interact with the entire JSONB blob.
But generally speaking, at some point, sometimes you have to do the less ergonomic thing in the name of performance. I'm just of a mind to postpone that until it's worth the tradeoff. Often, you can architect in such a way that such a change won't cascade through the rest of your system.
SQL should offer some native way to do this
After all, without a feature like this, you can't query on behalf on multiple users at a time without also encoding your RLS rules in some app queries, and caching becomes more difficult to implement as it now cannot be implemented independently of the app.
Is there any way to retrofit this behavior onto Postgres?
I wouldn't recommend it though, it ends up being a performance nightmare.
Operators cannot be made leakproof in RDS, so we had to choose between RDS and RLS.
Explain plans for the simplest queries get crazy. So when your perf is bad, it's hard to know why (so RLS gets blamed for more than its share, but it also does cause problems)
I'd be interested if you had more information.
Did you have only equality type RLS conditions or also more heavy ones too?
Our service now renders its own joins and subqueries, merging the client-based constraints with other application filtering criteria. We are never using prepared statements but instead dynamically render SQL where the client context is baked in as constants in the policy-enforcing filters. The query planner seems to do a much better job deciding on join and filtering orders, particularly when the application filtering criteria sparsify the result so that policies only need to be enforced on a small subset of the tables.
For RLS to match our current system, I think it would need a way to partially evaluate the policy, so it could reuse common subexpressions and treat them like constants during plan optimization.
[1] https://www.oracle.com/database/technologies/security/db-vau...
Thanks for pointing this out -- while I knew about various advanced Oracle features, I'd missed the Database Vault feature.
The multiverse database idea and Oracle's Database Vault are different, but somewhat complementary:
1) Database Vault is designed to protect sensitive application data against privileged users (DBAs, highly privileged role accounts). This is an important problem: administrator accounts are juicy targets, and restricting their access while still allowing maintenance activities is hard. Multiverse databases, as described in the paper, do not solve this problem, as the administrator still has access to the base universe. But ideas from Database Vault and its "realms" concept could be combined with the multiverse DB concept to achieve this!
2) Unlike multiverse databases, Database Vault does not protect the data against a buggy application, nor does it isolate different end-users within a single application from each other. In practice, this is where a lot of leaks do damage: a bug in the frontend either exposes information or can be exploited to expose it. Database Vault won't help here, as the leak does not even require a privileged user to be involved, and since the application runs inside a single realm.
You can see multiverse databases as the DB vault idea with application-level end-users each having their own realm. Making realms/universes work efficiently at scale, though, poses some serious systems research challenges. It also raises questions about how to write the policies defining what's visible to each end-user -- something that Database Vault doesn't have to deal with, because it merely requires an application-specific policy that indicates what information is sensitive and needs protecting.
Does that provide any clues? I honestly don't know since I don't know what that Oracle feature is under the hood.
Also, I'd point out that my initial reaction to your post was a bit hostile, but I noticed this is a paper so "how does it differ from this $PREVIOUS_WORK" is a fair question. I thought at first it was a project someone did, where that question is perhaps still fair, but a bit, ah, strong to lead with, shall we say.
My use-case lends itself well to this paradigm, though. Other apps might not be able to to this as well as mine.
I guess we'll have to wait for other use-cases!