News for hackers. Stuff that matters.
Re:Scaling Databases at Activision [pdf] by leetrout on Friday April 21, 2023 @01:13PM (#35656928)
When you give up one of the major components of relational databases like foreign keys you pick up lots of performance opportunity.

It is amazing what Vitess / PS will help you accomplish but they don't talk a lot about tradeoffs you make to get there (which are similar to what you face with sharding MySQL without additional tooling).

Re:Scaling Databases at Activision [pdf] by candiddevmike on Friday April 21, 2023 @01:41PM (#35657339)
Things can be really fast when you throw out referential integrity
Re:Scaling Databases at Activision [pdf] by samlambert on Friday April 21, 2023 @01:32PM (#35657215)
We have foreign keys coming soon!
Re:Scaling Databases at Activision [pdf] by XCSme on Tuesday April 25, 2023 @09:43AM (#35700354)
Hi Sam!

I stumbled upon your DB service several times, and considered it several times suggesting it as the DB of choice for my customers (uxwizz.com), but the pricing is a bit confusing/hard to estimate in my case, which makes it hard for me to recommend it. Any suggestions?

Re:Scaling Databases at Activision [pdf] by berkle4455 on Friday April 21, 2023 @01:50PM (#35657477)
Foreign keys are so overrated. Write good code and you don’t have to rely on the DB to enforce referential integrity. It’s the equivalent of running test cases with every db write.
Re:Scaling Databases at Activision [pdf] by vecter on Friday April 21, 2023 @02:26PM (#35657945)
I'm curious, how would you obviate the need for foreign keys with "good" code? Can you provide a toy example or a reference to an article so I can understand better? I've used NoSQL databases a long time ago and currently rely on on good ole PostgreSQL, but I'm having a hard time understanding how "good" code can be a better solution for managing relationships between data than a foreign key.
Re:Scaling Databases at Activision [pdf] by Yoric on Friday April 21, 2023 @02:49PM (#35658252)
I guess you can use indices instead of foreign keys? And somehow implement all the `ON DELETE CASCADE` manually within any transaction that removes the original row? Not sure how it's "good" code but it could be faster.
Re:Scaling Databases at Activision [pdf] by DasIch on Friday April 21, 2023 @03:11PM (#35658580)
A foreign key doesn't necessarily imply an index. If you are using postgres, you would have to add an index in addition to the foreign key, if you want one.

On delete cascade, depending on how many rows it cascades to, can be problematic because it's a very long running blocking operation. That's something one might want to do as a background operation and in batches. Although that won't make it faster.

Re:Scaling Databases at Activision [pdf] by sroussey on Friday April 21, 2023 @03:42PM (#35658954)
Faster in aggregate throughput can often be different from faster for a specific operation.

Personally, I find delete on cascade dangerous. I mean, lots of fun for a pen tester, sure…

Re:Scaling Databases at Activision [pdf] by Yoric on Sunday April 23, 2023 @06:26AM (#35675007)
> Personally, I find delete on cascade dangerous. I mean, lots of fun for a pen tester, sure…

Intriguing. Can you tell me more?

Re:Scaling Databases at Activision [pdf] by Yoric on Sunday April 23, 2023 @06:26AM (#35675001)
> A foreign key doesn't necessarily imply an index. If you are using postgres, you would have to add an index in addition to the foreign key, if you want one.

Sure, I meant that an index in which the key is primary.

> On delete cascade, depending on how many rows it cascades to, can be problematic because it's a very long running blocking operation. That's something one might want to do as a background operation and in batches. Although that won't make it faster.

That can definitely be a problem (just like destructor deallocation stampedes in C++ or Rust). Still less risky than cascading manually and asynchronously, I suspect.

Re:Scaling Databases at Activision [pdf] by berkle4455 on Friday April 21, 2023 @03:53PM (#35659106)
> for managing relationships between data than a foreign key.

You're conflating the concept of a normalized database with insanely slow DB-enforced referential integrity/foreign keys.

Toy example? Sure. Take a well-formed 3NF schema and disable foreign key constraints.

Re:Scaling Databases at Activision [pdf] by vecter on Friday April 21, 2023 @04:36PM (#35659714)
Sorry, assume I'm dense.

> Take a well-formed 3NF schema and disable foreign key constraints.

I'm familiar with 3NF, but can you expand on what this means and how it relates to foreign keys? Or just point me to an article, I don't want to waste your time. I did some googling but wasn't sure where to proceed from your post.

Re:Scaling Databases at Activision [pdf] by berkle4455 on Friday April 21, 2023 @05:36PM (#35660538)
Say you have a super basic setup:

  user = {user_id, email}
  order = {order_id, user_id}
order.user_id is a foreign key to user.user_id. That's a perfectly valid and reasonable way to organize things.

Enabling RDBMS-enforced foreign key constraints is the issue. It slows everything down dramatically.

Re:Scaling Databases at Activision [pdf] by vecter on Friday April 21, 2023 @05:44PM (#35660624)
I see, thanks. Basically just store the foreign keys yourself as columns in relevant tables and perform the joins in SQL without having the DB enforce FK integrity with every insertion/update/delete. Would it be fair to say that read speeds are unaffected by this?
Re:Scaling Databases at Activision [pdf] by berkle4455 on Friday April 21, 2023 @05:53PM (#35660729)
Yes. Quite literally the only difference is not enabling foreign key constraints. Read speeds unaffected correct.
Re:Scaling Databases at Activision [pdf] by kgeist on Saturday April 22, 2023 @04:47AM (#35664551)
>It slows everything down dramatically

How slower is it really? MySQL automically creates indexes for foreign keys so I don't think it slows down "dramatically", just an additional indexed retrieval?

Do you know of any benchmarks which show the difference?

Re:Scaling Databases at Activision [pdf] by Philip-J-Fry on Friday April 21, 2023 @05:46PM (#35660653)
They're not saying 3NF enables you to remove foreign keys. They are talking about removing foreign key constraints from your RDBMS of choice.

Something like SQL Server can enforce foreign key constraints if you explicitly tell it your relationships between tables. The downside is that having this referential integrity costs you performance as the database has to check your relations when inserting/updating/deleting rows. E.g. checking that a foreign key is pointing at a valid primary key, checking that you aren't leaving invalid foreign keys when deleting a primary key, etc. This is to prevent you inserting bad data into the database.

You can delete these constraints and still have the exact same behavior so long as your code is correct. It just means that the database isn't going to stop you writing bad data.

Re:Scaling Databases at Activision [pdf] by vecter on Friday April 21, 2023 @05:54PM (#35660747)
That makes sense. For workloads where write performance isn't very important but read performance is, this sounds like it may still be a worthwhile tradeoff to have that extra level of data integrity.

My sense is that many typical CRUD apps aren't writing gargantuan volumes of data or making very complex edits, and if they do, it's ok if it takes a second longer. Usually read speed is more of a bottleneck for user-facing applications, but I'm sure there are probably some examples where this tradeoff is worth it.

Re:Scaling Databases at Activision [pdf] by AlisdairO on Friday April 21, 2023 @07:23PM (#35661570)
> so long as your code is correct

This is a pretty tough definition of correct, though. Without foreign key constraints you'll have a really tough time dealing with concurrency artifacts without raising your isolation levels, which generally brings larger performance concerns.

Re:Scaling Databases at Activision [pdf] by remram on Saturday April 22, 2023 @09:23AM (#35666372)
Why do you think that?

My experience is that if you have a moderate amount of foreign keys, a lot of DBMS (not Postgres) will refuse the `ON DELETE CASCADE` (in the diamond case), and you have to do it "manually" anyway (from your query builder).

Re:Scaling Databases at Activision [pdf] by AlisdairO on Saturday April 22, 2023 @11:10AM (#35667339)
I think it because a significant fraction of my career has been spent fixing db-concurrency-related mistakes for people once they hit scale :-).

I’m not talking about using cascade - this applies perfectly well to use of on delete restrict. FKs are more or less the only standard way to reliably keep relationships between tables correct without raising up the isolation level (at least, in most dbs) or doing explicit locking schemes that would be slower than the implicit locking that foreign keys perform.

Re:Scaling Databases at Activision [pdf] by AlisdairO on Friday April 21, 2023 @06:04PM (#35660859)
How does this stay correct in the presence of concurrent activity?
Re:Scaling Databases at Activision [pdf] by berkle4455 on Friday April 21, 2023 @06:08PM (#35660902)
Using transactions or UUID/ULIDs though maybe I’m misunderstandingyour question. How do foreign key constraints help with concurrency?
Re:Scaling Databases at Activision [pdf] by AlisdairO on Friday April 21, 2023 @06:26PM (#35661070)
Table User: userid, etc

Table Resources: resourceid, userid, etc

If I want to restrict deletion of a user to only be possible after all the resources are deleted, I'm forced into using higher-than-default isolation levels in most DBs. This has significant performance implications. It's also much easier to make a mistake - for example, if when creating a resource I check that the user exists prior to starting the transaction, then start the tran, then do the work, it will allow insertion of data into a nonexistent user.

Re:Scaling Databases at Activision [pdf] by edf13 on Saturday April 22, 2023 @02:40AM (#35663979)
Add your user check as a where clause on the resources insert?
Re:Scaling Databases at Activision [pdf] by AlisdairO on Saturday April 22, 2023 @10:47AM (#35667087)
Can you give an example? I’m not aware of a mechanism like that that will protect you from concurrency artifacts reliably - certainly not a general one.
Re:Scaling Databases at Activision [pdf] by drwiggly on Saturday April 22, 2023 @04:48PM (#35670784)
start transaction;

select id from users where id = ? for update;

if row_count() < 1 then raise 'no user' end if;

insert into sub_resource (owner, thing) values (?, ?);

commit;

??

Re:Scaling Databases at Activision [pdf] by AlisdairO on Saturday April 22, 2023 @06:40PM (#35671559)
Do that in most relational dbs in the default isolation level (read committed), and concurrently executing transactions will still be able to delete users underneath you after the select.

If we take postgres as an example, performing the select takes exactly zero row level locks, and makes no guarantees at all about selected data remaining the same after you’ve read it.

Re:Scaling Databases at Activision [pdf] by paxys on Friday April 21, 2023 @08:13PM (#35661928)
You can have foreign keys (in the sense of a column on one table pointing to an ID column on another), just without the database itself enforcing the correctness of those relationships on every write.
Re:Scaling Databases at Activision [pdf] by AdrianB1 on Friday April 21, 2023 @02:04PM (#35657670)
From experience you are very right. Also from experience, most teams are not good enough to write the code with that quality that you can give up to referential integrity.
Re:Scaling Databases at Activision [pdf] by kgeist on Friday April 21, 2023 @03:03PM (#35658473)
"Write good code and you won't have bugs" :)

I think it's good practice to enforce consistency rules both in the DB and in code. If you make a mistake in your code, the DB won't allow it, and vice versa.

Re:Scaling Databases at Activision [pdf] by vp8989 on Friday April 21, 2023 @03:10PM (#35658568)
In theory it is good practice, but in practice enforcing referential integrity is not free and it makes satisfying other non-functional requirements harder. Engineering is about tradeoffs. Foreign keys are overkill in modern architectures where DBs/tables are typically only written to by a single application. They solve a problem that lots of people don't really have anymore.
Re:Scaling Databases at Activision [pdf] by kgeist on Friday April 21, 2023 @03:19PM (#35658669)
In the legacy project our team inherited, there's a lot of data consistency issues stemming from the lack of foreign keys (we're adding them back now). Data consistency is important because we deal with financial data. Typically, code and data change more often than DB schemas, so every release has a chance that someone will forget to update all relations manually in code, introducing dangling references, for example. Foreign keys help as an additional safety measure, because they don't change as often. I think you should care about the performance of foreign keys only when speed is more important than data consistency. It's a good default.
Re:Scaling Databases at Activision [pdf] by sroussey on Friday April 21, 2023 @03:39PM (#35658930)
Personally, I thinks foreign keys are great in dev and bad at any scale that you have many db servers.

And as you point out, there are exceptions, like financial data. But not marketing funnels where you might throw everything away.

You should probably have different types of engineers working on such different projects as well.

Re:Scaling Databases at Activision [pdf] by erik_seaberg on Saturday April 22, 2023 @06:49PM (#35671610)
> DBs/tables are typically only written to by a single application

I’ve seen several teams regret making this assumption. Unless you enforce draconian access control over a database, you’re going to discover that customer support and accounting and biz dev have been quietly relying on it.

Re:Scaling Databases at Activision [pdf] by baronvonsp on Friday April 21, 2023 @04:53PM (#35659953)
The exact analogy that came to mind for me.

Plus, relational databases don't just sit under a single application. There's usually multiple applications/services talking to them. Worse, humans connect to them an do all sorts of things they shouldn't do. That's the whole point of managing referential integrity in the DBMS, since you can only control "just write good code" across so many application domains.

Of course whether the performance tradeoff is worth it is a complicated decision for many of the reasons people have mentioned. But in 20 years of working with relational databases at big companies, I've seen few examples where the performance win exceeded the business risk.

Re:Scaling Databases at Activision [pdf] by iamflimflam1 on Friday April 21, 2023 @08:07PM (#35661892)
In my experience almost every time I've heard people saying they don't want foreign keys because of "the performance hit" - they've been nowhere near the scale or the skill that would make it sensible.
Re:Scaling Databases at Activision [pdf] by XCSme on Tuesday April 25, 2023 @09:49AM (#35700433)
I don't think foreign keys can be replaced by good code. Probably their main advantage is what happens if there are edge-cases or DB write fails, to make sure the referential integrity is maintained in outstanding circumstances.
Re:Scaling Databases at Activision [pdf] by _a_a_a_ on Friday April 21, 2023 @02:03PM (#35657652)
Databases are my interest, so if you don't mind… How would removal of foreign keys speed up read access?

I'm also going to disagree with you a little, again on the issue of reading, if you have foreign keys then you can do optimisations like cutting out chunks of joins. Adding constraints means you know more which you can feed to the optimiser which means often you can get better performance (read performance, that is).

Re:Scaling Databases at Activision [pdf] by robmccoll on Friday April 21, 2023 @03:14PM (#35658612)
Not OP, but they said that you pick up performance, not specifically in reading. The performance you gain is larger aggregate write throughput (and read generally - although reads that require spreading queries across shards and aggregating results will likely perform a little worse). You also gain scale in that you have turned something that was limited by scale up into something limited by scale out (while giving up some data guarantees and performance on some queries).

As to why you can't really have foreign keys, basically, sharding schemes like this sit at an intermediate layer between the application and the various DB clusters that are the shards. You CAN have strong data consistency (and useful foreign keys) within a shard because it's all inside a single database; however across shards, you CAN NOT. The sharding layer doesn't perform checks for you, so if you have two logical tables that are partitioned differently across the shards, you can't have a foreign key that will be enforced correctly as the foreign key of a given row in one table may live on a different shard in the other table. The local database within the shard would reject the insert. Transactions across shards can also be tricky to impossible.

Re:Scaling Databases at Activision [pdf] by _a_a_a_ on Friday April 21, 2023 @03:42PM (#35658958)
In my experience most databases are read-heavy so that's what I was asking about. That said, thanks for a clear explanation.
Re:Scaling Databases at Activision [pdf] by giovannibonetti on Friday April 21, 2023 @07:28PM (#35661604)
IIRC CockroachDB had (has?) interleaved tables for this reason. It seemed to allow collocating shards with the same foreign key in the same machine, leveraging composite keys for that.

For example, a multi-tenant application could have a tenants table with PK id, and an orders table with PK (tenant_id, id), and a FK from orders(tenant_id) to tenants(id). Then CockroachDB would keep the orders with tenant_id = 123 in the same machine where the tenant with id = 123 was.

I have the impression they deprecated interleaved tables, but I can't find more info about it.

Re:Scaling Databases at Activision [pdf] by doodlesdev on Friday April 21, 2023 @11:54PM (#35663202)
Here you go:

https://github.com/cockroachdb/cockroach/issues/52009

Not only deprecated, but completely removed a few years ago as seen in:

https://github.com/cockroachdb/cockroach/issues/69150

Re:Scaling Databases at Activision [pdf] by dub on Friday April 21, 2023 @11:08PM (#35662996)
The reasons Vitess didn't have foreign key support historically actually weren't a bold performance tradeoff or anything like that. It was more of a classic, boring, backlog prioritization thing: everyone heavily using Vitess was using gh-ost for schema changes, and gh-ost didn't support foreign keys.

Now that Vitess has native schema change tools it's more reasonable to revisit user-friendly, out-of-the-box foreign key support.

Re:Scaling Databases at Activision [pdf] by samlambert on Friday April 21, 2023 @11:14PM (#35663033)
Kind of. It was definitely an opinionated choice at some point, justified with performance. Now it is just something we need to add and it's nearly done. It will still have trade offs associated like all distributed systems.