2009-08-06 24 views
2

我有一個java web應用程序,從表中選擇一列(600萬行),它需要大量的CPU時間。這個select(SELECT id FROM mytable WHERE filename ='unique_filename')在查詢瀏覽器中執行時花費的時間要少得多。爲什麼SQL select在java中佔用更多的CPU時間?

這是什麼原因造成的?
我應該從哪裏開始尋找瓶頸?

數據庫是MSSQL 2005標準
爪哇容器是Tomcat的5.5(與sqljdbc 1.2)

更多細節:
1.Java代碼

ResultSet rs = null;  
PreparedStatement stmt = null; 
Connection conn = null; 
Integer myId=null; 
String myVeryUniqueFileName = strFromSomeWhere; 
try 
{ 
    conn = Database.getConnection(); 
    stmt = conn.prepareStatement("SELECT id FROM mytable WHERE filename = ?"); 
    stmt.setString(1, myVeryUniqueFileName); 

    rs = stmt.executeQuery(); 
    if (rs.next()) 
    { 
     myId= new Integer(rs.getInt(1)); 
    }    } 
    if (rs.next()) 
    { 
     throw new DBException("Duplicate myId: " + myId); 
    } 
    return myId; 
} catch (Exception e) { 
    // handle this 
} 

數據庫對象使用的DriverManager以接收連接對象。

2.SQL表格大約有30列。

CREATE TABLE [dbo].[calls]( 
    [id] [int] NOT NULL,  
    ...  
    [filename] [varchar](50) NOT NULL, 
    ...  
CONSTRAINT [PK_xxxxxxxxxxxx] PRIMARY KEY CLUSTERED  
( 
    [id] ASC  
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],  
CONSTRAINT [UQ_xxxxxxxxxxxx] UNIQUE NONCLUSTERED  
(  
    [filename] ASC  
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]  
) ON [PRIMARY]  

文件列是唯一的,因此結果集是allways 1或null。

+1

當你說的CPU時間,你的意思是在Java中使用的CPU應用程序還是數據庫服務器使用的CPU?他們在兩臺不同的機器上嗎? – 2009-08-06 14:39:29

+0

Tomcat和MSSQL在同一臺服務器上?在你的Java應用程序中存儲了600萬個ID值的對象是什麼? Java和.NET都需要時間創建和銷燬內存中的每個對象,並且如果需要創建600萬個對象,則需要大量時間。 – 2009-08-06 14:40:55

+0

這不是一個真正的問題?這不是很詳細,當然,但OP仍然可以解決這個問題。 – ChssPly76 2009-08-06 17:09:17

回答

2

在方式更聰明的開發人員的幫助下,我能夠解決這個問題。原來我濫用PreparedStatement(aricle)。

在此基礎上,我改變java代碼:

ResultSet rs = null;  
Statement stmt = null; 
Connection conn = null; 
Integer myId=null; 
String myVeryUniqueFileName = strFromSomeWhere; 
try 
{ 
    conn = Database.getConnection(); 
    stmt = conn.createStatement() 
    // 
    rs = stmt.executeQuery("SELECT id FROM mytable WHERE filename = '" 
         + myVeryUniqueFileName + "'"); 
    if (rs.next()) 
    { 
    myId= new Integer(rs.getInt(1)); 
    }    
    if (rs.next()) 
    { 
    throw new DBException("Duplicate myId: " + myId); 
    } 
    return myId; 
} catch (Exception e) { 
    // handle this 
} 

在此之後dababase負載從平均70%下降到13%

0

您描述的症狀通常是由緩存不正確的查詢計劃造成的。

重建索引或更新您的統計信息。

+0

我不會說查詢計劃與索引的重建直接相關。這似乎是你所暗示的。 – 2009-08-06 14:40:08

0

您正在使用一個聲明可能而不是準備好的聲明。一條語句不會被預編譯和緩存,所以查詢優化器必須每次都完成這項工作。如果您使用準備好的語句,它會嘗試並找到執行您的查詢的最佳方式,並將其存儲。下次您使用它時,不會費心去嘗試找出一個獲得結果的好方法,它將只是它已有的執行計劃。

1

你可以發佈你的Java代碼執行此查詢並檢索結果嗎?

導致Java代碼來出現到顯著不再採取可能的因素有:

  1. 您的查詢返回大量的記錄,你要找回他們都在Java中,而查詢瀏覽器只會顯示前100名(無論這個數字是多少),並根據需要加載其他人。
  2. 您正在比較不同的時間,例如查詢瀏覽器顯示的「查詢花費了X毫秒」,這與Java獲取連接直到關閉它的時間有關。
  3. 您的對象(保留結果)創建起來可能很昂貴,或者他們可能在填充後在幕後進行一些處理。
1

我無法專門與MSSQL 2005交談,但是在使用綁定變量的預準備語句和嵌入值的等價語句之間,執行計劃可能存在差異。

要測試此理論,請刪除綁定參數,然後將Java中的SQL查詢與實際文件名(用引號引起來)連接起來。這樣你就可以將蘋果與蘋果進行比較。

此外,它會有助於指示您遇到的CPU時間差異。是幾個數量級還是少於100%?

相關問題