如何水平组合两个查询?

时间:2017-02-13 17:37:01

标签: sql-server

我编写了以下查询:

SELECT u.LastName Col1
, convert(varchar, COALESCE(COUNT(DISTINCT pm.PhraseId), 0)) AS Col2
, convert(varchar, COALESCE(COUNT(DISTINCT pc.PhraseId), 0)) AS Col3
FROM dbo.AspNetUsers u
LEFT JOIN dbo.Phrase pm ON u.Id = pm.ModifiedBy
LEFT JOIN dbo.Phrase pc ON u.Id = pc.CreatedBy
GROUP BY u.LastName

性能极差,运行时间超过一分钟。

然后我尝试将其分解为两个查询,每个查询只需两秒钟即可运行:

SELECT u.LastName Col1
, convert(varchar, COALESCE(COUNT(DISTINCT pm.PhraseId), 0)) AS Col2
FROM dbo.AspNetUsers u
LEFT JOIN dbo.Phrase pm ON u.Id = pm.ModifiedBy
GROUP BY u.LastName

SELECT u.LastName Col1
, convert(varchar, COALESCE(COUNT(DISTINCT pc.PhraseId), 0)) AS Col2
FROM dbo.AspNetUsers
LEFT JOIN dbo.Phrase pm ON u.Id = pc.CreatedBy
GROUP BY u.LastName

由于第一个查询不可运行,我想找到一些方法来组合两个较小查询的输出。 这是我想与表DDL相处的结果:

我有两张桌子:

CREATE TABLE [dbo].[Phrase] (
    [PhraseId]     UNIQUEIDENTIFIER DEFAULT (newid()) NOT NULL,
    [English]      NVARCHAR (250)   NOT NULL,
    [CreatedBy]    INT              DEFAULT ((1)) NOT NULL,
    [ModifiedBy]   INT              DEFAULT ((1)) NOT NULL,
    PRIMARY KEY CLUSTERED ([PhraseId] ASC)
);

CREATE TABLE [dbo].[AspNetUsers] (
    [Id]                   INT            IDENTITY (1, 1) NOT NULL,
    [FirstName]            NVARCHAR (MAX) NULL,
    [LastName]             NVARCHAR (MAX) NULL,
    CONSTRAINT [PK_dbo.AspNetUsers] PRIMARY KEY CLUSTERED ([Id] ASC)
);

Col1       Col2        Col3

ad1        100           50
ad2        10             5
ad3        200           99

请注意,我的索引是这样的:

create nonclustered index ix_Phrase_CreatedBy on dbo.Phrase (CreatedBy)
create nonclustered index ix_Phrase_ModifiedBy on dbo.Phrase (ModifiedBy)

我很欣赏有关如何将较小的2秒运行时查询组合起来的建议,因为它似乎无论如何 我无法获得第一个快速运行的查询。不确定这是SQL Server问题还是

1 个答案:

答案 0 :(得分:0)

使用Paste The Plan @ brentozar.com

分享您的执行计划

正如我在这里提到的:Performance problems with two left joins. Is there an alternative with unpivot?

您也不需要使用count(distinct ...),因为PhraseId是唯一的,或coalesce()

rextester:http://rextester.com/CMP5250

select
    u.LastName
  , CreatedByQty =count(pc.CreatedBy)
  , ModifiedByQty=count(pm.ModifiedBy)
from dbo.AspNetUsers u
  left join dbo.Phrase pc
    on u.Id = pc.CreatedBy
  left join dbo.Phrase pm
    on u.Id = pm.ModifiedBy
group by u.LastName

你也可以尝试交换outer apply()的左连接,但我不知道这是否会有所帮助:

select
    u.LastName
  , CreatedByQty =count(pc.CreatedBy)
  , ModifiedByQty=pm.ModifiedByQty
from dbo.AspNetUsers u
  left join dbo.Phrase pc
    on u.Id = pc.CreatedBy
outer apply (
    select ModifiedByQty=count(1) 
    from dbo.Phrase pm
    where u.Id = pm.ModifiedBy
    ) pm
group by u.LastName
相关问题