2015-11-16 15 views
0

我只是想知道是否有人可以看到這個問題的更好的解決方案。SQL查詢優化(表結構更改後)

我以前有一個扁平(寬)表使用,包含多列。此表現在已更改爲僅包含2列(statistic_name和value)的動態表。

我修改了我的代碼以使用子查詢返回與以前相同的結果,但是我擔心在使用實際實時數據時性能會很糟糕。這是基於兩個版本之間差異很大的實踐計劃。

請參閱以下我的問題非常簡單的例子 -

CREATE TABLE dbo.TEST_FLAT 
(
    ID INT, 
    TEST1 INT, 
    TEST2 INT, 
    TEST3 INT, 
    TEST4 INT, 
    TEST5 INT, 
    TEST6 INT, 
    TEST7 INT, 
    TEST8 INT, 
    TEST9 INT, 
    TEST10 INT, 
    TEST11 INT, 
    TEST12 INT 
) 

CREATE TABLE dbo.TEST_DYNAMIC 
(
    ID INT, 
    STAT VARCHAR(6), 
    VALUE INT 
) 

CREATE TABLE dbo.TEST_URNS 
(
    ID INT 
) 

-- OLD QUERY 
SELECT D.[ID], D.TEST1, D.TEST2, D.TEST3, D.TEST4, D.TEST5, D.TEST6, D.TEST7, D.TEST8, D.TEST9, D.TEST10, D.TEST11, D.TEST12 
FROM [dbo].[TEST_URNS] U 
INNER JOIN [dbo].[TEST_FLAT] D 
ON D.ID = U.ID 

-- NEW QUERY 
SELECT U.[ID], 
(SELECT VALUE FROM dbo.TEST_DYNAMIC WHERE ID = U.ID AND STAT = 'TEST1') AS TEST1, 
(SELECT VALUE FROM dbo.TEST_DYNAMIC WHERE ID = U.ID AND STAT = 'TEST2') AS TEST2, 
(SELECT VALUE FROM dbo.TEST_DYNAMIC WHERE ID = U.ID AND STAT = 'TEST3') AS TEST3, 
(SELECT VALUE FROM dbo.TEST_DYNAMIC WHERE ID = U.ID AND STAT = 'TEST4') AS TEST4, 
(SELECT VALUE FROM dbo.TEST_DYNAMIC WHERE ID = U.ID AND STAT = 'TEST5') AS TEST5, 
(SELECT VALUE FROM dbo.TEST_DYNAMIC WHERE ID = U.ID AND STAT = 'TEST6') AS TEST6, 
(SELECT VALUE FROM dbo.TEST_DYNAMIC WHERE ID = U.ID AND STAT = 'TEST7') AS TEST7, 
(SELECT VALUE FROM dbo.TEST_DYNAMIC WHERE ID = U.ID AND STAT = 'TEST8') AS TEST8, 
(SELECT VALUE FROM dbo.TEST_DYNAMIC WHERE ID = U.ID AND STAT = 'TEST9') AS TEST9, 
(SELECT VALUE FROM dbo.TEST_DYNAMIC WHERE ID = U.ID AND STAT = 'TEST10') AS TEST10, 
(SELECT VALUE FROM dbo.TEST_DYNAMIC WHERE ID = U.ID AND STAT = 'TEST11') AS TEST11, 
(SELECT VALUE FROM dbo.TEST_DYNAMIC WHERE ID = U.ID AND STAT = 'TEST12') AS TEST12 
FROM [dbo].[TEST_URNS] U 

注意這是SQL2008 R2,這將是一個存儲過程的一部分,該表的平板版本包含的記錄數十萬(最後計算900k左右)。

在此先感謝。

+0

看起來像** [EAV](http:// stackoverflow。com/questions/1336449/eav-over-sql-server)** – lad2025

+0

它也將取決於您計劃添加多少數據。如果每月有數百萬的新行,則EAV(2 cols)模型會縮放問題 – Mihai

回答

1

在TEST_DYNAMIC的STAT列上創建索引以進行快速查找。

但首先考慮重新設計TEST_DYNAMIC變化STAT VARCHAR(6)STAT_ID INT(參照查找表) 然後在TEST_DYNAMIC,創建STAT_ID指數將運行相當快一點比文本字段索引。

+0

我很喜歡這個結構,但是我會要求索引應用於這些列,謝謝。 – user1948635

1

創建TEST_DYNAMIC和TEST_URNS表是這樣的:

CREATE TABLE [dbo].[TEST_DYNAMIC](
    [ID] [int] IDENTITY(1,1) NOT NULL, 
    [STAT] [varchar](50) NOT NULL, 
    [VALUE] [int] IDENTITY(1,1) NOT NULL, 
CONSTRAINT [PK_TEST_DYNAMIC] PRIMARY KEY CLUSTERED 
(
    [ID] 
)) 

CREATE TABLE dbo.TEST_URNS 
(
    ID [int] IDENTITY(1,1) NOT NULL 
) 
CONSTRAINT [PK_TEST_URNS] PRIMARY KEY CLUSTERED 
(
    [ID] 
)) 

如果你一段時間,業績變差的通知後,那麼你可以檢查索引碎片:

SELECT a.index_id, name, avg_fragmentation_in_percent 
FROM sys.dm_db_index_physical_stats (DB_ID(), OBJECT_ID(dbo.TEST_DYNAMIC'), 
NULL, NULL, NULL) AS a 
    JOIN sys.indexes AS b ON a.object_id = b.object_id AND a.index_id = b.index_id; 
GO 

然後你可以像這樣重建索引:

ALTER INDEX PK_PK_TEST_DYNAMIC ON dbo.TEST_DYNAMIC 
REBUILD; 
GO 

有關詳細信息,請參閱https://msdn.microsoft.com/en-us/library/ms189858.aspx

另外,我喜歡@Brett Lalonde的建議將STAT更改爲int。

+0

感謝您的迴應。我實際上不能修改表結構,但是我要求索引按照上面的方式創建。 – user1948635

+1

好,太好了。聚簇索引根據其鍵值對錶或視圖中的數據行進行物理存儲,因此使用這種類型的索引可能會獲得更好的性能。請參閱https://msdn.microsoft.com/en-CA/library/ms190457.aspx – Roger

1

真正知道的唯一方法就是試用它。一般來說,現代硬件應該能夠支持對性能影響不大的任何查詢,只要你正確地對兩個表建立索引(你可能需要一個關於ID和STAT的索引)。

如果你有900K個實體和12個屬性,你就有大約1000萬行;那應該罰款一個體面的serer。最終,如果每個月添加多條記錄,則可能會遇到性能問題。

更大的問題是,您粘貼的示例查詢幾乎肯定不是您最終在真實查詢中運行的結果。如果您必須在派生表上篩選和/或比較TEST5和TEST6,那麼如果它們是「真實」列,則您無法從其他索引中受益。

然後,您可以繞過圈並將您的EAV表執行爲indexed view

+0

Thankyou,請牢記這一點。 – user1948635