views:

94

answers:

4

I have 2 tables that their rows have one on one relation.. For you to understand the situation, suppose there is one table with user informations and there is another table that contains a very specific informations and each user can only link to one these specific kind of informations ( suppose second table as characters )

And that character can only assign to the user who grabs it, Is it against the rules of designing clean databases to hold the relation key in both tables?

User Table: user_id, name, age, character_id

Character Table: character_id, shape, user_id

I have to do it for performance, how do you think about it?

+2  A: 

Yes, I'd say it was against the rules of designing clean databases, as the data you have is repeated, therefore you have to actively maintain two sets of data at all times for fear they are out of sync. If you don't do this, you can't trust the data. :)

As a side note: You say you're doing this for performance reasons? What benefits have you seen of doing this? As regardless of which table you access the data from, you should find (with proper indexes) that there is very little difference? It might be you are fixing the wrong issue here and maybe there are other things to look at first (like indexes, improving your queries etc).

Edit: Selecting free characters should be easy enough as you would get rid of the character_id from the users table and only have user_id in the characters one:

Users:  user_id, name, age
Characters:  character_id, shape, user_id

Then you would be able to do some queries like these:

//something like this to query for free characters.
SELECT * FROM characters WHERE user_id IS NULL;

// To access a list of a users characters, you could do something like this:
SELECT * FROM characters WHERE user_id = 42;

// More information about the user, while still grabbing character info.
SELECT * FROM characters AS c INNER JOIN users AS u ON u.user_id = c.user_id WHERE u.user_id = 42;

Or is there more about your model that I'm maybe missing with this? (As I don't pretend to know your database layout ;) ). I'm assuming a one-to-many relationship, as it does appear to be that way (one user can have many characters).

Amadiere
What if I wanna find free characters?select * from characters where character_id not in (select character_id from users where character_id = %d)
EBAGHAKI
No, you are perfectly right! :D
EBAGHAKI
Updated answer to try and clarify the alternative. I don't know if I come across as critical, though I certain don't intend to. :) Just trying to raise a question or two in your head, as you know your situation better :)
Amadiere
The problem with this is that suppose there are 1000 users in database, so if i want to check each user one by one (and not all together by left joins) i have to query characters table for each of them. that's very costly
EBAGHAKI
Checking 1000 rows one by one should not be costly on any modern RDBMS. What exactly do you mean "check each user", thougH?
Adam Robinson
You want to check in what way, what do you want to find out? You can still do single user `WHERE` clauses on joins if you don't want all the user info. e.g. `SELECT * FROM Users AS u LEFT OUTER JOIN Characters AS c ON c.user_id = u.user_id WHERE u.user_id = 34;` I'm guessing with that query, but maybe I'm again not quite with what the issue is. But I'd say that when you say "very costly", it's worth checking - as the costly things aren't always the things you'd expect :)
Amadiere
SELECT * FROM Users AS u LEFT OUTER JOIN Characters AS c ON c.user_id = u.user_id WHERE u.user_id = 34; This is hardly a costly operation if you have indexed the FK as well as the PK. If you haven't indexed, yes it is costly.
HLGEM
thank you guys! this site is the best when somebody like you explains thigs!
EBAGHAKI
+6  A: 

In a 1:1 relationship there still should be a record that would be considered the "parent".

In this case, I would consider user to be hierarchically above character, so only use the foreign key in the character table.

Peter Bailey
+2  A: 

Couple of reasons:

  • Redundant data
  • Need to keep both the tables always updated with the correct keys...

I would look at the reasons for the performance problems since this is a 1:1 relation, you will get the single record pretty quickly when you join on the PK:FK

Sunny
A: 

It is certainly possible to split data like this for performance reasons, particularly if you are working with lots of data in lots of columns: you may for example just put "basic" user info in one table and detailed stuff (eg. with large text fields) in another because these are not accessed as often as the basic things. Maybe you need full text capabilities on parts of the data so you use tables with different storage engines. If ebaghaki needs to do it for performance reasons, i'd say its ok - be sure though, that you app ensures the validity of the keys (or use triggers to keep things up to date?).

An alternative would be to build a lookup table which just holds references to the user and character tables. Then you wouldn't have any problems with null values for users that haven't chosen a character or characters that no users have chosen. This is probably your best bet because you aren't splitting the table for any of the reasons mentioned above.

Jon Gilbert