2015-11-16 14 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