2011-03-10 146 views
1

早上,所有的SQL Server數據庫的訪問速度,增加數以百萬計的記錄

我有一個網站,我就這一工作大約2000頁的代碼,它是一個社交媒體網站的企業。它有數百萬用戶的潛力。目前我們有大約80,000個用戶,並且網站訪問速度越來越慢。我在網站中使用98%的存儲過程來提高速度。我想知道的是我能做些什麼來提高數據提取速度並增加網站加載時間。我的知識是數據庫的成員表沒有使用全文索引,這會有所作爲嗎?我想它會搜索。但是,例如,登錄時需要一段時間才能加載。下面是登錄腳本SP:

SELECT 
a.MemberID, 
CAST (ISNULL(a.ProfileTypeID,0) AS bit) AS HasProfile, 
a.TimeOffsetDiff * a.TimeOffsetUnits AS TimeOffset, 
b.City, 
b.StateName AS State, 
b.StateAbbr AS abbr, 
b.Domain, 
b.RegionID, 
a.ProfileTypeID, 
sbuser.sf_DisplayName(a.MemberID) AS DisplayName, 
a.UserName, 
a.ImgLib, 
a.MemberREgionID AS HomeRegionID, 
a.StateID, 
a.IsSales, 
a.IsAdmin 
FROM Member a 
INNER JOIN Region b ON b.RegionID = a.MemberRegionID 
WHERE a.MemberID = @MemberID 

UPDATE Member SET NumberLogins = (NumberLogins + 1) WHERE MemberID = @MemberID 

考慮到這一點僅通過80000會員獵可能需要長達15秒登錄,我認爲這是真正的慢。有關如何提高登錄速度的任何想法?

顯然,提取成員列表到頁面也很費力。我最近更新包含的臨時數據集之類的尋呼和用下面的例子取代它過時的TF腳本:

IF @MODE = 'MEMBERSEARCHNEW' 
DECLARE @TotalPages INT 
BEGIN 
    SELECT @TotalPages = COUNT(*)/@PageSize 
    FROM Member a 
    LEFT JOIN State b ON b.StateID = a.StateID 
    WHERE (sbuser.sf_DisplayName(a.MemberID) LIKE @UserName + '%') 
    AND a.MemberID <> @MemberID; 

    WITH FindSBMembers AS 
    (
     SELECT ROW_NUMBER() OVER(ORDER BY a.Claimed DESC, sbuser.sf_MemberHasAvatar(a.MemberID) DESC) AS RowNum, 
     a.MemberID,            -- 1 
     a.UserName,            -- 2 
     a.PrCity,             -- 3 
     b.Abbr,             -- 4 
     sbuser.sf_MemberHasImages(a.MemberID) AS MemberHasImages, -- 5 
     sbuser.sf_MemberHasVideo(a.MemberID) AS MemberHasVideo, -- 6 
     sbuser.sf_MemberHasAudio(a.MemberID) AS MemberHasAudio, -- 7 
     sbuser.sf_DisplayName(a.MemberID) AS DisplayName,   -- 8 
     a.ProfileTypeID,           -- 9 
     a.Zip,              -- 10 
     a.PhoneNbr,            -- 11 
     a.PrPhone,             -- 12 
     a.Claimed,             -- 13 
     @TotalPages AS TotalPages         -- 14 
     FROM Member a 
     LEFT JOIN State b ON b.StateID = a.StateID 
     WHERE (sbuser.sf_DisplayName(a.MemberID) LIKE @UserName + '%') 
     AND a.MemberID <> @MemberID 
    ) 
    SELECT * 
    FROM FindSBMembers 
    WHERE RowNum BETWEEN (@PG - 1) * @PageSize + 1 
    AND @PG * @PageSize 
    ORDER BY Claimed DESC, sbuser.sf_MemberHasAvatar(MemberID) DESC 
END 

是否有另一種方式我可以擠出更多的速度出這個腳本..?

我有其他建議,包括gzip壓縮,根據字母表中的字母將成員表分成26個表。我很想知道大公司如何做,他們如何安排他們的數據,像Facebook,Yelp,黃頁,Twitter等網站。我目前正在共享託管服務器上運行,升級到VPS或專用服務器有助於提高速度。

該網站是用傳統的ASP,利用SQL Server 2005的

任何幫助,任何你可以提供將不勝感激。

最好的問候和快樂編碼!

保羅

****開始。此外:

set ANSI_NULLS ON 
set QUOTED_IDENTIFIER ON 
GO 



ALTER FUNCTION [sbuser].[sf_DisplayName](@MemberID bigint) 
RETURNS varchar(150) 

AS 

BEGIN 
DECLARE @OUT varchar(150) 
DECLARE @UserName varchar(50) 
DECLARE @FirstName varchar(50) 
DECLARE @LastName varchar(50) 
DECLARE @BusinessName varchar(50) 
DECLARE @DisplayNameTypeID int 

SELECT 


    @FirstName = upper(left(FirstName, 1)) + right(FirstName, len(FirstName) - 1), 
    @LastName = upper(left(LastName, 1)) + right(LastName, len(LastName) - 1) , 
    @BusinessName = upper(left(BusinessName, 1)) + right(BusinessName, len(BusinessName) - 1), 
    @UserName = upper(left(UserName, 1)) + right(UserName, len(UserName) - 1), 
    /* 
    @FirstName = FirstName, 
    @LastName = LastName, 
    @BusinessName = BusinessName, 
    @UserName = UserName, 
    */ 
    @DisplayNameTypeID = DisplayNameTypeID 
    FROM Member 
    WHERE MemberID = @MemberID 

    IF @DisplayNameTypeID = 2 -- FIRST/LAST NAME 
     BEGIN 
      /*SET @OUT = @FirstName + ' ' + @LastName*/ 
      SET @OUT = @LastName + ', ' + @FirstName 
     END 
    IF @DisplayNameTypeID = 3 -- FIRST NAME/LAST INITIAL 
     BEGIN 
      SET @OUT = @FirstName + ' ' + LEFT(@LastName,1) + '.' 
     END 
    IF @DisplayNameTypeID = 4 -- BUSINESS NAME 
     BEGIN 
      SET @OUT = @BusinessName + '' 
     END 

    RETURN @OUT 
END 

****加成END

+2

你怎麼知道性能問題是在SQL服務器上? – 2011-03-10 16:39:03

+0

還有什麼...... ..?洗耳恭聽..! – neojakey 2011-03-10 16:43:20

+0

在SQL Management Studio中運行該存儲過程,或爲代碼添加一些時間。找出頁面的哪些特定部分需要這麼長時間,以便確保將您的努力付諸正確。 – 2011-03-10 16:48:42

回答

0

放在主鍵和外鍵indexes( MemberID,RegionID,MemberRegionID)

+0

PK和FK默認情況下索引只存在? – jocull 2012-09-07 19:50:55

+0

只有PKs被自動編入索引(至少在SQL Server中) – Cosmin 2012-09-10 13:18:39

0

最初的想法

這裏的問題可能不是你的存儲過程。特別是關於登錄腳本,您將注意力集中在一個小而無關緊要的地方,因爲登錄命令是一次性成本,並且您可以對這些頁面的腳本執行時間有更高的容忍度。

您正在使用經典的ASP,現在已經過時了。當你處理如此多的訪問者時,你的服務器將需要很大的權力來管理它正在解釋的所有請求。解釋後的頁面將比編譯頁面慢。

時間事件

如果你確信數據庫在你的腳本是緩慢的,使用次數。在頁面頂部添加一個通用計時器,以及一個SQL計時器。

頁面開始加載,初始化一般時間。到達存儲過程時,啓動SQL計時器。查詢完成後,停止SQL計時器。在頁面末尾有兩個計時器,一個計算運行SQL的時間,另一個計時器 - SQL計時器爲您提供執行代碼的總時間。這有助於您在效率方面將數據庫從代碼中分離出來。

提高ASP頁面的性能

我有詳細的良好ASP頁面設計在這裏:

VBScript Out Of Memory Error

還認爲:

  • 使用Option Explicit在你的頁面的頂部。
  • 設置Response.Buffer = True
  • 用Response.write內<%%>,反覆打開和關閉這些緩慢

我再次重申我在鏈接的答案說,到目前爲止,迄今您可以爲性能做的最好的事情是將記錄集結果轉儲到.getRows()的數組中。不要循環記錄集。不要選擇不使用的查詢中的字段。每個頁面只有1個記錄集和1個ado連接。我真的建議你閱讀好的ASP頁面設計的鏈接。

升級,如果沒有炫目的問題

什麼是服務器的規格?在這種情況下升級硬件可能是提高性能的最佳途徑,並且在成本/回報方面效率最高。

0

@Tom Gullen - 在這種情況下,使用經典ASP似乎是無關緊要的,因爲在這種情況下計算的實際成本似乎與SQL(或任何數據庫技術這是運行)。

@the問題 - 我的Cosmin與同意,索引表中的相關領域將提供一定的性能增益,假設他們沒有這樣做。

我們有一個這種情況,一個星期前,我的老闆試圖從批處理文件中執行多個條件插入,這個批處理文件是永久存在的。我們在一個userid字段中放置一個索引,然後嘿,同樣的腳本花了大約一分鐘的時間來執行。

索引!

+0

@neojakey - 你在使用SQL Studio嗎?如果是這樣,請嘗試從SQL Studio客戶端中運行SP。單擊將運行存儲過程的腳本,然後單擊頂部的查詢菜單,然後單擊「包括實際執行計劃」。一旦查詢完成,您應該看到一些明確的數字顯示此腳本可能執行的時間。如果您然後索引被測試的列(即WHERE子句正在測試的那些列)並再次運行腳本,則應該看到結果的執行計劃選項卡中第二批數字的速度有所提高。祝你好運! – BizNuge 2011-03-11 08:55:25

2

80000不是很多記錄,除非你沒有索引,或者你的數據類型很大。如果該查詢真的是你的下一個瓶子,那麼你可能要考慮在成員表和區域表上創建覆蓋索引。

以memberid爲索引在成員表上創建索引,幷包括profiletypeid,timeoffsetdiff,timeoffsetunits,profiletypeid,memberid,用戶名,imglib,memberregionid,stateid,issales,isadmin。

也,僅僅指剛注意到你的函數sbuser.sf_DisplayName(a.memberID)。你可能會探索這個功能,以確保這不是你的真正瓶頸。

+0

提及UDF的+1。看起來它必須是非確定性的(帶一個MemberID並返回一個字符串,可能表示一個表查找),因此對該函數的每次調用都會導致對錶的單獨訪問,並且必須在表過濾前可能會發生... – 2011-03-10 16:53:24

+0

而同樣的函數被調用兩次表中的每一行(談論成員搜索過程)。確認! – 2011-03-10 16:55:13

+0

@克里斯,我不使用功能,所以我不知道他們很多,除了他們可以是真正的瓶頸。 udf必須在應用where子句之前爲表中的每個記錄執行?太瘋狂了。 fi這是真的,那麼我幾乎打賭udf是問題。 – DForck42 2011-03-10 16:56:28

1

加速sf_DisplayName的第一個選項是從成員中添加FirstName,LastName等作爲參數,並使用它構建DisplayName而不是對成員表進行查找。

之後,你可以考慮到顯示名稱添加爲計算並持續列成員表。這意味着DisplayName將在成員保存時計算,並且在執行查詢時將使用保存的值。您還可以在DisplayName列上添加索引。

GetDisplayName函數必須以with schemabinding

create function dbo.GetDisplayName(
    @FirstName varchar(50), 
    @LastName varchar(50), 
    @DisplayNameType int) 
returns varchar(102) with schemabinding 
as 
begin 
    declare @Res varchar(102) 
    set @Res = '' 
    if @DisplayNameType = 1 
    set @Res = @FirstName+' '[email protected] 

    if @DisplayNameType = 2 
    set @Res = @LastName+', '[email protected] 

    return @Res 
end 

與持久列顯示名稱

CREATE TABLE [dbo].[Member](
    [ID] [int] NOT NULL, 
    [FirstName] [varchar](50) NOT NULL, 
    [LastName] [varchar](50) NOT NULL, 
    [DisplayNameType] [int] NOT NULL, 
    [DisplayName] AS ([dbo].[GetDisplayName]([FirstName],[LastName],[DisplayNameType])) PERSISTED, 
CONSTRAINT [PK_Member] PRIMARY KEY CLUSTERED 
(
    [ID] ASC 
) 
) 

上顯示名稱

索引的表創建
CREATE INDEX [IX_Member_DisplayName] ON [dbo].[Member] 
(
    [DisplayName] ASC 
) 

你也應該有一個仔細看看你在sf_MemberHasImages,0123中做什麼和sf_MemberHasAudio。它們用在cte的列表中。不像在where子句中使用的那樣糟糕,但它們仍然可能導致您遇到問題。

最後一個我發現一個潛在的問題是sf_MemberHasAvatar。它在兩個地方用於order by。但row_number()中的訂單由於在主要查詢中的過濾而被用於where where子句WHERE RowNum BETWEEN (@PG - 1) * @PageSize + 1

使用持續柱中所描述的技術可能能夠對其他功能使用爲好。

0

要替換UDF,如果出現這個問題,我建議在Member表中有一個字段用於存儲DisplayName,因爲從函數的外觀來看,數據似乎相當靜態。您只需要在開始時更新該字段一次,然後纔可以在有人註冊或更改DisplayNameTypeID時使用。我希望這對你有幫助。

1

快速ñ骯髒的方式採取UDF喊一聲「每一行」的

SELECT *, sbuser.sf_DisplayName(MemberID) FROM (

    SELECT 
    a.MemberID, 
    CAST (ISNULL(a.ProfileTypeID,0) AS bit) AS HasProfile, 
    a.TimeOffsetDiff * a.TimeOffsetUnits AS TimeOffset, 
    b.City, 
    b.StateName AS State, 
    b.StateAbbr AS abbr, 
    b.Domain, 
    b.RegionID, 
    a.ProfileTypeID, 
    a.UserName, 
    a.ImgLib, 
    a.MemberREgionID AS HomeRegionID, 
    a.StateID, 
    a.IsSales, 
    a.IsAdmin 
    FROM Member a 
    INNER JOIN Region b ON b.RegionID = a.MemberRegionID 
    WHERE a.MemberID = @MemberID 

) 
+0

我正在考慮這些方面,但與udf的不積極,我不知道它是否會工作。 – DForck42 2011-03-10 19:09:13

1

另一種方式,如果你不希望修改任何表,是剛剛把UDF邏輯的選擇聲明:

case DisplayNameTypeID 
     when 2 then upper(left(LastName, 1)) + right(LastName, len(LastName) - 1) + ', ' + upper(left(FirstName, 1)) + right(FirstName, len(FirstName) - 1) 
     when 3 then upper(left(FirstName, 1)) + right(FirstName, len(FirstName) - 1) + ' ' + upper(left(LastName, 1)) 
     when 4 then upper(left(BusinessName, 1)) + right(BusinessName, len(BusinessName) - 1) 
    end as DisplayName 

是啊它看起來有點gorey,但你所要做的就是修改sp。