I have a stored procedure that looks up an article based on the article's title. But I also need to increment a column in the same table that counts the number of times the article is viewed.
Trying to be as efficient as possible, I see two possible ways to approach this:
Perform one SELECT to obtain the PK on the target row. Then use that PK to increment the number of views and, finally, another SELECT using the PK to return the article data.
Perform one SELECT to return the article data to my application, and then use the returned PK to make another round trip to the database to increment the number of views.
I know #1 would be pretty fast, but it's three lookups. And #2 requires two round trips to the database. Is there no way to optimize this task?
EDIT Based on feedback, I came up with the following. Thanks for any comments or constructive criticism.
DECLARE @Slug VARCHAR(250) -- Stored procedure argument
-- declare @UpdatedArticle table variable
DECLARE @UpdatedArticle TABLE
(
ArtID INT,
ArtUserID UNIQUEIDENTIFIER,
ArtSubcategoryID INT,
ArtTitle VARCHAR(250),
ArtHtml VARCHAR(MAX),
ArtDescription VARCHAR(350),
ArtKeywords VARCHAR(250),
ArtLicenseID VARCHAR(10),
ArtViews BIGINT,
ArtCreated DATETIME2(7),
ArtUpdated DATETIME2(7)
);
UPDATE Article
SET ArtViews = ArtViews + 1
OUTPUT
INSERTED.ArtID,
INSERTED.ArtUserID,
inserted.ArtSubcategoryID,
INSERTED.ArtTitle,
INSERTED.ArtHtml,
INSERTED.ArtDescription,
INSERTED.ArtKeywords,
INSERTED.ArtLicenseID,
INSERTED.ArtViews,
INSERTED.ArtUpdated,
INSERTED.ArtCreated
INTO @UpdatedArticle
WHERE ArtSlugHash = CHECKSUM(@Slug) AND ArtSlug = @Slug AND ArtApproved = 1
SELECT a.ArtID, a.ArtUserID, a.ArtTitle, a.ArtHtml, a.ArtDescription, a.ArtKeywords, a.ArtLicenseID,
l.licTitle, a.ArtViews, a.Ar开发者_如何学CtCreated, a.ArtUpdated, s.SubID, s.SubTitle, c.CatID, c.CatTitle,
sec.SecID, sec.SecTitle, u.UsrDisplayName AS UserName
FROM @UpdatedArticle a
INNER JOIN Subcategory s ON a.ArtSubcategoryID = s.SubID
INNER JOIN Category c ON s.SubCatID = c.CatID
INNER JOIN [Section] sec ON c.CatSectionID = sec.SecID
INNER JOIN [User] u ON a.ArtUserID = u.UsrID
INNER JOIN License l ON a.ArtLicenseID = l.LicID
Here is a way using the OUTPUT statement (SQL Server 2005 onwards), in a single update statement:
IF OBJECT_ID ('Books', 'U') IS NOT NULL
DROP TABLE dbo.Books;
CREATE TABLE dbo.Books
(
BookID int NOT NULL PRIMARY KEY,
BookTitle nvarchar(50) NOT NULL,
ModifiedDate datetime NOT NULL,
NumViews int not null CONSTRAINT DF_Numviews DEFAULT (0)
);
INSERT INTO dbo.Books
(BookID, BookTitle, ModifiedDate)
VALUES
(106, 'abc', GETDATE()),
(107, 'Great Expectations', GETDATE());
-- declare @UpdateOutput1 table variable
DECLARE @UpdateOutput1 table
(
BookID int,
BookTitle nvarchar(50),
ModifiedDate datetime,
NumViews int
);
-- >>>> here is the update of Numviews and the Fetch
-- update Numviews in Books table, and retrive the row
UPDATE Books
SET
NumViews = NumViews + 1
OUTPUT
INSERTED.BookID,
INSERTED.BookTitle,
INSERTED.ModifiedDate,
INSERTED.NumViews
INTO @UpdateOutput1
WHERE BookID = 106
-- view updated row in Books table
SELECT * FROM Books;
-- view output row in @UpdateOutput1 variable
SELECT * FROM @UpdateOutput1;
精彩评论