我只是想知道是否有人能够找到更好的解决方案来解决这个问题。
我以前有一个平坦的(宽)表可以使用,包含多个列。此表现已更改为仅包含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 :(得分: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。