At first glance, I see lots of inconsistent naming--Person_ID
, but PasswordHash
(or worse, SchoolYear_ID
). Pick a naming convention, and stick with it. I promise you that your future self with thank you!
On your Classes
table, you have a Student_ID
column. As far as school goes, many students take one class, so class should have a 1:n relationship with students, not a 1:1 relationship. I'd make a Class_Registration
table that contains a class id and a student id.
Also, unless your score can be different that what it ought to be based on your performance (say, a professor giving you a boost), you shouldn't have a StudentScores
table. That should be derived from the number of questions you answered correctly.
I don't see any worrisome circular references, so I think you're good on that front.
Ensuring that addresses are unique is not a trivial problem. You have to assume that people enter their addresses in slightly different ways, abbreviating some parts sometimes, or omitting optional information. Just checking for exact duplicates would probably fail pretty often.
You should consider whether trying to keep addresses unique is worth the effort and complexity.
Addresses of users and addresses of orders are pretty different concepts. A user can change their current address. An order should never be retroactively changed in that way, the address there should always be the delivery address.
You could consider making addresses immutable. Changing an address would always mean creating a new address. This means you can safely point orders to the common address table, as the addresses will never change.
If a user changes their address, you simply add a new address and link it to the user. The old address can be hidden in the UI, soft-deleted or just shown as an address history. But all orders could still reference the old address because it never changes.
- Is it practical, at scale, to scan an entire table to see if an Address exists before adding it?
That depends entirely on what you consider "at scale", it's not an issue with a few tens of thousands of rows but completely impractical with a billion rows.
- Is an index supporting a combination of eight columns reasonable (as in Option 1)?
B-Tree indexes are limited to something around 2700 characters. Indexing very large items is typically not a good idea. In Postgres 10, which isn't released yet, you could consider a hash index for this which has a fixed size as far as I understand and should have an advantage for large columns.
But I really think you're asking the wrong question here. In your application, you should know when an address is already in the DB because the user didn't enter it from scratch, but e.g. selected it from the list of addresses already associated with their account.
You don't actually need to enforce uniqueness in your DB, if I understand your problem correctly. And if you'd need to do that, you should always use a unique constraint, which automatically uses an index.
Best Answer
A simple list of name/address pairs with an index on each would be sufficient if absolutely all you needed to do was lookup one from the other. Unfortunately you will find that the DNS protocol has larger requirements than that so if you intending to interact with the public domain name system you have much more work ahead of you. See http://en.wikipedia.org/wiki/Domain_Name_System for a quick primer and a list of the relevant RFCs (which are essentially the specification you'd be expected to work to as a participant in the public DNS infrastructure (though remember that many features are optional: you may chose to implement an authoritative service only so not need to worry about recursive queries (except knowing the right error response to give when you receive one).
There are a couple of F/OSS DNS servers that use a relational database back-end instead of bind-style zone files, perhaps you could look at their structures as a hint (though if you are building a commercial solution be careful of licensing issues: for instance you might find looking at GPL covered code to be a bad idea if you intend to distribute the results of your project in a non-GPL compatible manner):
MyDNS: http://mydns.bboy.net/
Power DNS: http://en.wikipedia.org/wiki/PowerDNS