LEFT JOIN对比一张桌子

时间:2017-09-11 17:58:35

标签: sql-server join

我工作的公司经常出于性能原因在多个表中拆分实体,因为只有一小部分表具有这些属性。实体Item的属性将分为两到七个表作为规范化命令。 这是一个可行的策略吗?

我运行了下面的查询并将LEFT JOIN与完整表格进行了比较(最后两个查询)。为什么LEFT JOIN变慢?在这个论坛上,您了解了关系数据库应如何处理这些问题。然而,执行计划以批量成本的11%估计全表查询。客户统计数据也有利于整个表格。

我在查询中遗漏了什么?或者LEFT JOIN比完整的表慢?

Comparison of LEFT JOIN vs one table

Comparison of LEFT JOIN vs one table(2): here you can clearly see the second query is slower in seconds

CREATE TABLE
    [Item] (
    [Id] INT IDENTITY(1, 1) NOT NULL,
    [Property1] VARCHAR(50) NOT NULL,
    [Property2] VARCHAR(50) NULL,
    [Property3] VARCHAR(50) NULL,
    [Property4] VARCHAR(50) NULL,
    [Property5] VARCHAR(50) NULL,
    [Property6] VARCHAR(50) NULL,
    [Property7] VARCHAR(50) NULL,
    [Property8] VARCHAR(50) NULL,
    [Property9] VARCHAR(50) NULL,
    [Property10] VARCHAR(50) NULL,
    [Property11] VARCHAR(50) NULL,
    [Property12] VARCHAR(50) NULL,
    [Property13] VARCHAR(50) NULL,
    [Property14] VARCHAR(50) NULL,
    [Property15] VARCHAR(50) NULL,
    [Property16] VARCHAR(50) NULL,
    [Property17] VARCHAR(50) NULL,
    [Property18] VARCHAR(50) NULL,
    [Property19] VARCHAR(50) NULL,
    [Property20] VARCHAR(50) NULL
 CONSTRAINT [PK_Item] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY];
GO

DECLARE @i INT = 106
WHILE @i < 3009286
BEGIN
    EXEC ('INSERT INTO [Item] ([Property1]) VALUES (' + @i + ')');
    EXEC ('INSERT INTO [Item2] ([Property1]) VALUES (' + @i + ')');
    SET @i = @i + 1
END

CREATE TABLE
    [Item2] (
    [Id] INT IDENTITY(1, 1) NOT NULL,
    [Property1] VARCHAR(50) NOT NULL
 CONSTRAINT [PK_Item2] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY];
GO


CREATE TABLE
    [ItemProperties1] (
    [Id] INT IDENTITY(1, 1) NOT NULL,
    [ItemId] INT NOT NULL,
    [Property1] VARCHAR(50) NOT NULL,
    [Property2] VARCHAR(50) NULL,
    [Property3] VARCHAR(50) NULL,
    [Property4] VARCHAR(50) NULL,
    [Property5] VARCHAR(50) NULL,
    [Property6] VARCHAR(50) NULL,
    [Property7] VARCHAR(50) NULL,
    [Property8] VARCHAR(50) NULL,
    [Property9] VARCHAR(50) NULL
 CONSTRAINT [PK_ItemProperties1] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY];
GO


CREATE TABLE
    [ItemProperties2] (
    [Id] INT IDENTITY(1, 1) NOT NULL,
    [ItemId] INT NOT NULL,
    [Property10] VARCHAR(50) NULL,
    [Property11] VARCHAR(50) NULL,
    [Property12] VARCHAR(50) NULL,
    [Property13] VARCHAR(50) NULL,
    [Property14] VARCHAR(50) NULL,
    [Property15] VARCHAR(50) NULL,
    [Property16] VARCHAR(50) NULL,
    [Property17] VARCHAR(50) NULL,
    [Property18] VARCHAR(50) NULL,
    [Property19] VARCHAR(50) NULL,
    [Property20] VARCHAR(50) NULL
 CONSTRAINT [PK_ItemProperties2] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY];
GO

CREATE NONCLUSTERED INDEX [IX_ItemProperties_ItemId] ON [ItemProperties1]
(
    [ItemId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_ItemProperties_ItemId] ON [ItemProperties2]
(
    [ItemId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
GO

SELECT
    *
FROM
    Item

SELECT
    *
FROM
    Item2
LEFT JOIN
    ItemProperties1 ON Item2.Id = ItemProperties1.ItemId
LEFT JOIN
    ItemProperties2 ON Item2.Id = ItemProperties2.ItemId

2 个答案:

答案 0 :(得分:1)

这是一个可行的策略吗?
是的,它被称为垂直分片/垂直分区。它背后的想法是你的列的百分比将被更多地使用,所以想法是将这些列放在更快的硬件上,也取决于你如何实现分片,它将使索引更小,从而更适合的。但我们需要知道您的公司如何垂直分片/垂直分区数据库。你真的使用分区表吗?或者某些DBA只是在两个表上打了两个索引并引用它们?

例如(不使用MS表分区)

表A:
ID
Col A
Col B

表A分区表
标识
Col C
Col D

猜测为什么左连接速度较慢(因为我不知道你是如何分片/分区你的表,​​是它必须做2 聚集索引扫描以提取数据,然后使用嵌套连接将数据放在一起,然后扫描分区表并使用嵌套连接将这些数据重新组合在一起。

因此,必须做更多工作才能使数据看起来像逻辑上的一个表。

<强> 修改

我没有完全看你的代码,你没有使用microsofts分区表功能。This is a good base walkthrough

<强> 修改 如果你打算使用分区表,你需要几件事,我怀疑你是否正在使用这些。但是,如果您可以在数据库和分区模式中找到分区函数,那么您的公司可能正在对表进行分区。

  1. A partition function

  2. A partition schema

答案 1 :(得分:0)

通常,JOIN比在一个表中包含所有内容要慢:即使它已经过优化,您仍然需要在多个位置查找相同的值。通常情况下,如果您将更多数据(或列)返回给应用程序而不是需要,那么仅仅因为传输成本就会影响性能。

这可行吗? 是的。几乎每个CMS都做类似的事情,最后我检查WordPress是非常重要的。

这是一个好主意吗? 定义“好”。这通常会让您拥有一个更小,高性能的表,您可以根据需要随意加入较小的数据表。这意味着您应该根据需要更轻松地加入其他来源。

这是否会影响性能? 如果您能够在89%的行中实现性能的轻微提升,则可以减少11%的行其他行的表现。