Saturday, 27 July 2013

SQL Server Database Design - Facebook Profile and Friends



SQL Server Database Design - Facebook Profile and Friends

If the database of Facebook was implemented using SQL Server, how would the database structure look like?  Here's an attempt of designing a database structure that can be used to store profile information and connections (also known as Friends) similar to the ones used by Facebook.

Disclaimer: The author of this article does not work for Facebook and has not worked for Facebook.  It is just the author's attempt on designing the database that may work on such site as Facebook.  Any similarities to the database design implemented by Facebook are mere coincidences (and luck).
The basic building block or the basic element in Facebook is an account. When a user signs up, the user is asked for the following information:
  • First Name
  • Last Name
  • Email Address
  • Password
  • Birthdate
  • Gender
Given these information, we can now create the first table in our database design, which we will call the Account table:
CREATE TABLE [dbo].[Account](
    [AccountID]  INT IDENTITY(1,1) NOT NULL,
    [Email]      VARCHAR(100) NOT NULL,
    [FirstName]  VARCHAR(50) NOT NULL,
    [LastName]   VARCHAR(50) NOT NULL,
    [Password]   VARBINARY(100) NOT NULL,
    [Birthdate]  DATE NOT NULL,
    [Gender]     CHAR(1) NOT NULL,
    CONSTRAINT [PK_Account] PRIMARY KEY CLUSTERED ( [AccountID] ASC )
)
GO

Other user information such as relationship status, website, anniversary, religion and political views, can be added to this table later but the basic requirements for now are just these columns.
Once an account has been created, the next thing a user usually does is to add new friends by doing a friend request.  
The friend request event can be stored in a table, which we will appropriately call FriendRequest.

CREATE TABLE [dbo].[FriendRequest](
    [FriendRequestID]     INT IDENTITY(1,1) NOT NULL,
    [AccountID1]          INT NOT NULL REFERENCES [dbo].[Account] ( [AccountID] ),
    [AccountID2]          INT NOT NULL REFERENCES [dbo].[Account] ( [AccountID] ),
    [RequestDate]         DATETIME NOT NULL,
    CONSTRAINT [PK_FriendRequest] PRIMARY KEY CLUSTERED ( [FriendRequestID] ASC )
)
GO

If a friend request has been declined, that record will be removed from this table.  However, if the friend request has been accepted then that friend can now be associated with the user.   This account association will be maintained in another table, appropriately called the Friend table.

CREATE TABLE [dbo].[Friend](
    [FriendID]   [int] IDENTITY(1,1) NOT NULL,
    [AccountID1] [int] NOT NULL REFERENCES [dbo].[Account] ( [AccountID] ),
    [AccountID2] [int] NOT NULL REFERENCES [dbo].[Account] ( [AccountID] ),
    PRIMARY KEY CLUSTERED ( [FriendID] ASC )
)
GO

The friend request record will be deleted from the [dbo].[FriendRequest] table and two records will be created in the [dbo].[Friend] table. The first record will be the association between the user (as AccountID1) and the friend (as AccountID2) and the second record will be the opposite which is the relationship between the friend (as AccountID1) and the user (as AccountID2).

Although the [dbo].[FriendRequest] table can be merged together with the [dbo].[Friend] table and just add another column to signify the acceptance of the request, a separate table is used instead to separate the friends from friend requests to minimize the number of records being stored and queried when getting the list of friends for a particular user and thus making the query faster.

To get the list of friends for a particular user account, the following query can be used:
SELECT B.[Email], B.[FirstName], B.[LastName]
FROM [dbo].[Friend] A INNER JOIN [dbo].[Account] B
                              ON A.[AccountID1] = @AccountID AND
A.[AccountID2] = B.[AccountID]

To get a list of common friends between two user accounts, the following query can be used:
SELECT C.[Email], C.[FirstName], C.[LastName]
FROM [dbo].[Friend] A INNER JOIN [dbo].[Friend] B
                              ON A.[AccountID1] = @AccountID1 AND
B.[AccountID1] = @AccountID2 AND
A.[AccountID2] = B.[AccountID2]
                      INNER JOIN [dbo].[Account] C
                              ON A.[AccountID2] = C.[AccountID]

To make these queries execute faster, an indexes can be created on the [AccountID1] and [AccountID2] columns:
CREATE UNIQUE NONCLUSTERED INDEX [IX_Friend1] ON [dbo].[Friend] (
         [AccountID1] ASC,
         [AccountID2] ASC
)
GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_Friend2] ON [dbo].[Friend] (
         [AccountID2] ASC,
         [AccountID1] ASC
)
GO

No comments:

Post a Comment