T-SQL:获取多级产品类别时减少查询负载

时间:2017-04-29 17:10:21

标签: sql tsql sql-server-2016

我正在[products]中存储[products_category_mapping]中分配了产品的类别。 可以将产品分配到级别0,1和2中的类别。因此,产品将在[products_category_mapping]中出现1,2或3次,具体取决于产品的分配级别。

然后我想通过查询检索这些产品所属类别的数据。 这些查询非常昂贵,因为它们包含大量连接,我们需要检查每个类别级别产品是否出现在该级别。此外,还有大约200,000种产品,每种产品分配到1,2或3个类别,因此运行下面的查询需要很长时间。

我的问题:如何优化这些查询的效果?

PS。请不要建议重新设计表格,看看我们在这个过程中的位置,现在还不行。

当前查询:

SELECT label_nl+';'+slug_nl as labelslug_nl_0,label_en+';'+slug_en as labelslug_en_0,label_nl as label_nl_0,label_en as label_en_0,slug_nl as slug_nl_0,slug_en as slug_en_0
,pagetitle_nl as pagetitle_nl_0,pagetitle_en as pagetitle_en_0,image_nl as image_nl_0,image_en as image_en_0
,description_nl as description_nl_0,description_en as description_en_0
,metadescription_nl as metadescription_nl_0,metadescription_en as metadescription_en_0 
FROM articlegroups ga WITH (NOLOCK)
INNER JOIN products_category_mapping pcm on pcm.articlegroup_id=ga.id
INNER JOIN products gp on gp.id=pcm.artikelid
WHERE gp.id=3216743 AND ga.catlevel=0

SELECT label_nl+';'+slug_nl as labelslug_nl_0,label_en+';'+slug_en as labelslug_en_0,label_nl as label_nl_0,label_en as label_en_0,slug_nl as slug_nl_0,slug_en as slug_en_0
,pagetitle_nl as pagetitle_nl_0,pagetitle_en as pagetitle_en_0,image_nl as image_nl_0,image_en as image_en_0
,description_nl as description_nl_0,description_en as description_en_0
,metadescription_nl as metadescription_nl_0,metadescription_en as metadescription_en_0 
FROM articlegroups ga WITH (NOLOCK)
INNER JOIN products_category_mapping pcm on pcm.articlegroup_id=ga.id
INNER JOIN products gp on gp.id=pcm.artikelid
WHERE gp.id=3216743 AND ga.catlevel=1   

SELECT label_nl+';'+slug_nl as labelslug_nl_2,label_en+';'+slug_en as labelslug_en_2,label_nl as label_nl_2,label_en as label_en_2,slug_nl as slug_nl_2,slug_en as slug_en_2
,pagetitle_nl as pagetitle_nl_2,pagetitle_en as pagetitle_en_2,image_nl as image_nl_2,image_en as image_en_2
,description_nl as description_nl_2,description_en as description_en_2
,metadescription_nl as metadescription_nl_2,metadescription_en as metadescription_en_2 
FROM articlegroups ga WITH (NOLOCK)
INNER JOIN products_category_mapping pcm on pcm.articlegroup_id=ga.id
INNER JOIN products gp on gp.id=pcm.artikelid
WHERE gp.id=3216743 AND ga.catlevel=2

DDL

USE [mydb]
GO
/****** Object:  Table [dbo].[articlegroups]    Script Date: 29-04-2017 18:34:13 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[articlegroups](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [parentid] [int] NOT NULL,
    [catlevel] [tinyint] NOT NULL,
    [label_nl] [nvarchar](50) NOT NULL,
    [label_en] [nvarchar](50) NOT NULL,
    [slug_nl] [nvarchar](50) NOT NULL,
    [slug_en] [nvarchar](50) NOT NULL,
    [pagetitle_nl] [nvarchar](100) NULL,
    [pagetitle_en] [nvarchar](100) NULL,
    [image_nl] [nvarchar](50) NULL,
    [image_en] [nvarchar](50) NULL,
    [description_nl] [nvarchar](500) NOT NULL,
    [description_en] [nvarchar](500) NULL,
    [metadescription_nl] [nvarchar](200) NULL,
    [metadescription_en] [nvarchar](200) NULL,
    [createdate] [datetime] NOT NULL,
    [canonicalurl_nl] [nvarchar](150) NULL,
    [canonicalurl_en] [nvarchar](150) NULL,
 CONSTRAINT [PK_articlegroups] 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
ALTER TABLE [dbo].[articlegroups] ADD  CONSTRAINT [DF_articlegroups_lvl0_catlevel]  DEFAULT ((0)) FOR [catlevel]
GO
ALTER TABLE [dbo].[articlegroups] ADD  CONSTRAINT [DF_articlegroups_createdate]  DEFAULT (getdate()) FOR [createdate]
GO





USE [mydb]
GO
/****** Object:  Table [dbo].[products_category_mapping]    Script Date: 29-04-2017 18:33:59 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[products_category_mapping](
    [artikelid] [int] NOT NULL,
    [articlegroup_id] [int] NOT NULL,
    [createdate] [datetime] NOT NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[products_category_mapping] ADD  CONSTRAINT [DF_products_category_mapping_createdate]  DEFAULT (getdate()) FOR [createdate]
GO
ALTER TABLE [dbo].[products_category_mapping]  WITH CHECK ADD  CONSTRAINT [FK_articlegroups_lvl1_mapping_products] FOREIGN KEY([artikelid])
REFERENCES [dbo].[products] ([id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[products_category_mapping] CHECK CONSTRAINT [FK_articlegroups_lvl1_mapping_products]
GO
ALTER TABLE [dbo].[products_category_mapping]  WITH CHECK ADD  CONSTRAINT [FK_products_category_mapping_articlegroups] FOREIGN KEY([articlegroup_id])
REFERENCES [dbo].[articlegroups] ([id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[products_category_mapping] CHECK CONSTRAINT [FK_products_category_mapping_articlegroups]
GO





USE [mydb]
GO
/****** Object:  Table [dbo].[products]    Script Date: 29-04-2017 18:33:12 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[products](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [friendlyurl] [nvarchar](200) NULL,
 CONSTRAINT [PK_products] 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






USE [mydb]
GO
SET IDENTITY_INSERT [dbo].[articlegroups] ON 
GO
INSERT [dbo].[articlegroups] ([id], [parentid], [catlevel], [label_nl], [label_en], [slug_nl], [slug_en], [pagetitle_nl], [pagetitle_en], [image_nl], [image_en], [description_nl], [description_en], [metadescription_nl], [metadescription_en], [createdate], [canonicalurl_nl], [canonicalurl_en]) VALUES (129, 0, 0, N'Baby / Geboorte', N'Baby and birth', N'baby-en-geboorte', N'baby-and-birth', N'Baby- en geboorte producten online kopen', N'Baby and birth', N'', N'', N'Alle baby en geboorte artikelen in 1 overzicht. Van kinderwagens tot baby-monitors tot commodes tot de inrichting van de kraamkamer.', N'', N'Online baby en geboorte producten kopen kan hier. Goedkope producten die jou helpen wanneer je net een  baby hebt!', N'', CAST(N'2016-04-12T23:31:43.003' AS DateTime), NULL, NULL)
GO
INSERT [dbo].[articlegroups] ([id], [parentid], [catlevel], [label_nl], [label_en], [slug_nl], [slug_en], [pagetitle_nl], [pagetitle_en], [image_nl], [image_en], [description_nl], [description_en], [metadescription_nl], [metadescription_en], [createdate], [canonicalurl_nl], [canonicalurl_en]) VALUES (680, 129, 1, N'Geboortekaartjes', N'Birth announcement', N'geboorte-kaartjes', N'birth-announcement-cards', N'Baby & Geboortekaartjes bestellen, drukken en versturen', N'Birth Announcements & Baby Birth Announcement Cards', N'', N'', N'Baby & geboortekaartjes bestel je in onze webshop. Wij hebben een flink aanbod in mooie en leuke kaartjes voor baby en geboorte. Schattige kaartjes bestellen.', N'', N'Leuke kaartjes voor baby & geboorte kun je hier eenvoudig bestellen. Originele en leuke kaarten speciaal voor de kleintjes.', N'', CAST(N'2016-04-12T23:31:43.310' AS DateTime), NULL, NULL)
GO
SET IDENTITY_INSERT [dbo].[articlegroups] OFF
GO

SET IDENTITY_INSERT [dbo].[products] ON 
GO
INSERT [dbo].[products] ([id],[friendlyurl]) VALUES (3216743, N'birth-with-flowers')




INSERT [dbo].[products_category_mapping] ([artikelid], [articlegroup_id], [createdate]) VALUES (3216743, 129, CAST(N'2017-04-24T20:05:58.463' AS DateTime))
GO
INSERT [dbo].[products_category_mapping] ([artikelid], [articlegroup_id], [createdate]) VALUES (3216743, 680, CAST(N'2017-04-24T20:05:58.463' AS DateTime))
GO

**更新1 **

根据评论中@HABO的建议,我尝试使用case语句来组合3个查询:

SELECT
CASE 
    when ga.catlevel=0 THEN
         label_nl+';'+slug_nl as labelslug_nl_0,label_en+';'+slug_en as labelslug_en_0,label_nl as label_nl_0,label_en as label_en_0,slug_nl as slug_nl_0,slug_en as slug_en_0
        ,pagetitle_nl as pagetitle_nl_0,pagetitle_en as pagetitle_en_0,image_nl as image_nl_0,image_en as image_en_0
        ,description_nl as description_nl_0,description_en as description_en_0
        ,metadescription_nl as metadescription_nl_0,metadescription_en as metadescription_en_0 
    when ga.catlevel=1 THEN
         label_nl+';'+slug_nl as labelslug_nl_1,label_en+';'+slug_en as labelslug_en_1,label_nl as label_nl_1,label_en as label_en_1,slug_nl as slug_nl_1,slug_en as slug_en_1
        ,pagetitle_nl as pagetitle_nl_1,pagetitle_en as pagetitle_en_1,image_nl as image_nl_1,image_en as image_en_1
        ,description_nl as description_nl_1,description_en as description_en_1
        ,metadescription_nl as metadescription_nl_1,metadescription_en as metadescription_en_1 
    else null
END
FROM globos_articlegroups ga WITH (NOLOCK)
INNER JOIN globos_products_category_mapping pcm on pcm.articlegroup_id=ga.id
INNER JOIN globos_products gp on gp.id=pcm.artikelid
WHERE gp.id=3216743 AND ga.catlevel in (0,1,2) 

但是我还不清楚,我怎样才能确定如何根据猫的等级来区分列:0,1或2

更新2

我得到了所需的结果集,但它有多行我想合并到一行。当有多行时,每列的最大值始终为1,其他值为NULL。我想将多行合并为一行,其中每列的最高值(即不是NULL)将保留。

当前结果集

  <table>
    <tbody>
      <tr>
        <th>labelslug_nl_0
        </th>
        <th>labelslug_nl_1
        </th>
        <th>labelslug_nl_2
        </th>
      </tr>
      <tr>
        <td>Baby / Geboorte;baby-en-geboorte
        </td>
        <td>NULL
        </td>
        <td>NULL
        </td>
      </tr>
      <tr>
        <td>NULL
        </td>
        <td>Geboortekaartjes;geboorte-kaartjes
        </td>
        <td>NULL
        </td>
      </tr>
    </tbody>
  </table>

所需的结果集

  <table>
    <tbody>
      <tr>
        <th>labelslug_nl_0
        </th>
        <th>labelslug_nl_1
        </th>
        <th>labelslug_nl_2
        </th>
      </tr>
      <tr>
        <td>Baby / Geboorte;baby-en-geboorte
        </td>
        <td>Geboortekaartjes;geboorte-kaartjes
        </td>
        <td>NULL
        </td>
      </tr>
    </tbody>
  </table>

1 个答案:

答案 0 :(得分:1)

此单个查询将检索三个查询返回的所有行。 CatLevel 01行将填充第一组列,并使第二组填充空值。 CatLevel 2行将反其道而行。

select
  case when AG.CatLevel in ( 0, 1 ) then label_nl + ';' + slug_nl end as labelslug_nl_0,
  case when AG.CatLevel in ( 0, 1 ) then label_en + ';' + slug_en as labelslug_en_0,
  case when AG.CatLevel in ( 0, 1 ) then label_nl end as label_nl_0,
  case when AG.CatLevel in ( 0, 1 ) then label_en end as label_en_0,
  case when AG.CatLevel in ( 0, 1 ) then slug_nl end as slug_nl_0,
  case when AG.CatLevel in ( 0, 1 ) then slug_en end as slug_en_0,
  case when AG.CatLevel in ( 0, 1 ) then pagetitle_nl end as pagetitle_nl_0,
  case when AG.CatLevel in ( 0, 1 ) then pagetitle_en end as pagetitle_en_0,
  case when AG.CatLevel in ( 0, 1 ) then image_nl end as image_nl_0,
  case when AG.CatLevel in ( 0, 1 ) then image_en end as image_en_0,
  case when AG.CatLevel in ( 0, 1 ) then description_nl end as description_nl_0,
  case when AG.CatLevel in ( 0, 1 ) then description_en end as description_en_0,
  case when AG.CatLevel in ( 0, 1 ) then metadescription_nl end as metadescription_nl_0,
  case when AG.CatLevel in ( 0, 1 ) then metadescription_en end as metadescription_en_0,
  case when AG.CatLevel = 2 then label_nl + ';' + slug_nl end as labelslug_nl_2,
  case when AG.CatLevel = 2 then label_en + ';' + slug_en as labelslug_en_2,
  case when AG.CatLevel = 2 then label_nl end as label_nl_2,
  case when AG.CatLevel = 2 then label_en end as label_en_2,
  case when AG.CatLevel = 2 then slug_nl end as slug_nl_2,
  case when AG.CatLevel = 2 then slug_en end as slug_en_2,
  case when AG.CatLevel = 2 then pagetitle_nl end as pagetitle_nl_2,
  case when AG.CatLevel = 2 then pagetitle_en end as pagetitle_en_2,
  case when AG.CatLevel = 2 then image_nl end as image_nl_2,
  case when AG.CatLevel = 2 then image_en end as image_en_2,
  case when AG.CatLevel = 2 then description_nl end as description_nl_2,
  case when AG.CatLevel = 2 then description_en end as description_en_2,
  case when AG.CatLevel = 2 then metadescription_nl end as metadescription_nl_2,
  case when AG.CatLevel = 2 then metadescription_en end as metadescription_en_2
  from ArticleGroups as AG inner join
    Products_Category_Mapping as PCM on PCM.ArticleGroup_Id = AG.Id inner join
    Products as P on P.Id = PCM.ArtikelId
  where P.Id = 3216743 and AG.CatLevel in ( 0, 1, 2 )

请注意,引用的所有列都应包含别名,例如: AG.Label_NL。这是OP的练习。