3
\$\begingroup\$

I am not a DBA nor do I play one on TV.

My application is retrieving information from Facebook and storing it into our own database. I want to retrieve the Location Post information of Id and AuthorId. AuthorId is a foreign key to another table. I was told by a DBA that foreign keys should always use internal unique identifiers because you can never rely on external unique identifiers. So I created the following table structure...

CREATE TABLE tblAuthor
(
 [MyAuthorId] INT NOT NULL PRIMARY KEY IDENTITY
 [FacebookAuthorId] BIGINT NOT NULL
 ...Additional Facebook information...
)
CREATE TABLE tblLocationPost
(
 [MyLocationPostId] INT NOT NULL PRIMARY KEY IDENTITY, 
 [FacebookLocationPostId] BIGINT NOT NULL, 
 [MyAuthorId] INT NOT NULL,
 ...Additional Facebook information...
 CONSTRAINT [FK_tblLocationPost_Author] FOREIGN KEY (MyAuthorId) REFERENCES tblAuthor(MyAuthorId)
)

The data I get back from Facebook when querying Location Post is LocationPostId and AuthorId. So I have created the following stored procedure to insert/update the LocationPost information in the database...

CREATE PROCEDURE [dbo].[LocationPost_Save]
@facebookLocationPostId bigint,
@facebookAuthorId bigint
AS
BEGIN
 DECLARE @myAuthorId INT
 DECLARE @IdentityColumn TABLE ( IdentityId int )
 BEGIN TRANSACTION
 /* Locate out internal unique id using facebooks unique author id, insert it if necessary */
 IF EXISTS (SELECT * FROM tblAuthor WHERE FacebookAuthorId = @facebookAuthorId)
 BEGIN
 SELECT @myAuthorId = MyAuthorId FROM tblAuthor WHERE FacebookAuthorId = @facebookAuthorId
 END
 ELSE
 BEGIN
 INSERT INTO tblAuthor (FacebookAuthorId) VALUES (@facebookAuthorId)
 SELECT @myAuthorId = SCOPE_IDENTITY()
 END
 /* Insert/Update one row in LocationPost */
 MERGE tblLocationPost lp
 USING (SELECT @facebookId as FacebookId) fb
 ON (lp.FacebookId = fb.FacebookId)
 WHEN MATCHED THEN 
 UPDATE SET 
 MyAuthorId = @myAuthorId,
 ...Additional data...
 WHEN NOT MATCHED THEN
 INSERT 
 (FacebookLocationPostId, MyAuthorId, ...Additional Columns...)
 VALUES 
 (@facebookLocationPostId, @myAuthorId, ...Additional Values...)
 OUTPUT INSERTED.MyLocationPostId INTO @IdentityColumn;
 COMMIT TRANSACTION
 /* Return the identify column of Inserted/Updated row */
 SELECT IdentityId FROM @IdentityColumn
END
  1. Is this the correct pattern to use for this scenerio or is there a better approach?

  2. Is the MERGE command the appropriate approach to Insert/Update a record (I am using SQL Server 2008)?

  3. Do I really need to put my own Author Unique Id in the LocationPost table, or can I simplify this by putting the Facebook Unique Id?

asked Nov 19, 2012 at 17:59
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Generally, the way I see the whole "don't allow external primary key" bit, is when an external entities are attempting to declare internal primary keys that your system has to manage. When you're essentially mirroring somebody else's system (as you are here), there's no point, because you have to use their primary keys to match up the records anyways (meaning, you'd essentially have two primary keys, with the same effect, you just 'trust' one 'less'). \$\endgroup\$ Commented Nov 19, 2012 at 21:26

1 Answer 1

1
\$\begingroup\$
  1. I'd rather use the FacebookAuthorId and FacebookLocationPostId as primary keys, because your logic ensures them to be unique. In case of your current solution you would still require (unique) indexes on these fields (in order for lookups to be efficient) so there is no reason not to use them as primary keys.
  2. Given suggest optimization you don't need to check/insert an author record LocationPost_Save, just use the merge to insert/update the data in the table, and create a separate Author_Save SP that will do the same job for Authors.

Having said that, assuming that you are using one of the high-level languages :) and you're developing a long-living solution I would actually recommend you to use one of the ORMs available for your language to interact with the database. It'll take a bit longer at the beginning, but you'll get a more flexible solution in a long term.

answered Nov 19, 2012 at 18:51
\$\endgroup\$
2
  • \$\begingroup\$ On your note about ORM's. I have always heard they are not efficient because they do not precompile the T-SQL statements as stored procedures do. Is this no longer true? Our application could potentially have hundreds (maybe even thousands) of hits a second during certain times of day. \$\endgroup\$ Commented Nov 20, 2012 at 15:12
  • \$\begingroup\$ You should not be worried about pre-compilation at this stage as it's an example of "premature optimization" (google this term). And answering your question - no, they don't suffer from not being pre-compiled because most DBMS (and SQL Server, of course) cache execution plans ("compiled T-SQL statements") and thus ORM-generated statements will still be as quick as stored procedures. You might require a tuning stage where you profile queries generated in order to optimize the performance where necessary, but that stage should be done after you've got real-world usage statistics \$\endgroup\$ Commented Nov 21, 2012 at 10:58

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.