SQL查询优化(表结构更改后)

时间:2015-11-16 16:55:15

标签: sql sql-server sql-server-2008

我只是想知道是否有人能够找到更好的解决方案来解决这个问题。

我以前有一个平坦的(宽)表可以使用,包含多个列。此表现已更改为仅包含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左右)。

提前致谢。

3 个答案:

答案 0 :(得分:1)

在TEST_DYNAMIC的STAT列上创建索引,以便快速查找。

但首先考虑重新设计TEST_DYNAMIC,将STAT varchar(6)更改为STAT_ID int(引用查找表) 然后在TEST_DYNAMIC上,在STAT_ID上创建一个索引,它将比文本字段上的索引运行得快得多。

答案 1 :(得分: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。

答案 2 :(得分:1)

真正了解的唯一方法就是尝试一下。通常,只要您正确地索引两个表(现在可能需要ID和STAT的索引),现代硬件应该能够支持任一查询,而对性能几乎没有明显的影响。

如果你有900K实体和12个属性,你有大约1000万行;那个应该对一个体面的服务员来说没问题。最终,如果每月添加许多记录,可能会遇到性能问题。

更大的问题是,您粘贴的示例查询几乎肯定不是您最终在真实查询中运行的内容。如果你必须在派生表上过滤和/或比较TEST5和TEST6,那么你就不会受益于你可以做的额外索引,如果它们是真实的"列。

然后你可以完整地圈出你的EAV表作为indexed view