【问题标题】:Query and table optimization查询和表优化
【发布时间】:2015-01-14 05:49:35
【问题描述】:

`

SELECT DISTINCT ECS.UserId,,PFR.EntityId,PFR.CreatedBy
FROM EventConsentStatus ECS 
INNER JOIN @Institutions I ON ECS.InstitutionId=I.InstitutionId             
LEFT JOIN ParentFormResponses PFR ON  PFR.EntityTypeId = 1 
          AND PFR.EntityId=@ActivityId AND ECS.EventId=PFR.EntityId                 
WHERE ECS.EventId = @ActivityId

上述查询中提到的名为ParentFormResponses 的表有超过3 条lacs 记录。表没有任何标识列,而是我根据唯一性在某些列的组上创建了聚集主索引。但是执行一个简单的选择语句仍然需要超过 16 分钟,即select * from ParentFormResponses

如果我从上面提到的 select 语句中删除 ParentFormResponses 表的列名,那么它会在 2 3 秒内显示结果,但对于上面的查询,它需要太多时间。

如果我在 entityid 和 entitytypeid 上创建非聚集索引,那么它也不会给出优化结果。

请建议我如何改进表结构和查询性能。

详细信息: 表结构:

`CREATE TABLE [dbo].[ParentFormResponses](
[EntityId] [int] NOT NULL,
[FormId] [int] NOT NULL,
[StudentId] [nvarchar](50) NOT NULL,
[CreatedBy] [nvarchar](50) NOT NULL,
[CreatedOn] [datetime] NOT NULL,
[EntityTypeId] [int] NOT NULL,
[FormVersion] [decimal](18, 1) NOT NULL,
[DigitallySigned] [bit] NULL,
[HasResponseChanged] [bit] NULL,

CONSTRAINT [PK_ParentFormResponses] 主键集群 ( [实体 ID] ASC, [FormId] ASC, [学生编号] ASC, [EntityTypeId] ASC, [表格版本] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY] ) 在 [PRIMARY] 上`

=> 我删除了主键索引并在非聚集索引下创建 CREATE NONCLUSTERED INDEX [IX_ParentFormResponses_sakshi_EntityId] ON [dbo].[ParentFormResponses_sakshi] ( [EntityId] ASC, [EntityTypeId] ASC, [FormId] ASC, [FormVersion] ASC ) INCLUDE ( [StudentId], [CreatedBy]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO

=> 基于 sp_spaceused 的所有三个表的结果是-

  • 名称-行、保留、数据、索引大小、未使用
  • ParentFormResponses - 309961、64704 KB、63592 KB、936 KB、176 KB
  • ParentFormResponses_sakshi- 309893、117696 KB、60472 KB、56944 KB、280 KB
  • EventConsentStatus - 673796、380920 KB、109240 KB、271512 KB、168 KB
  • 注意:记录数不是 30k 而是超过 3 lacs。不小心写错了。

    【问题讨论】:

    • 你知道什么是查询计划吗?如果没有 - 读取已完成。并张贴。也就是说,首先要实现 Distinct 盈余。这可能需要在 tempdb 上做很多工作,但是查询计划会告诉你。
    • 从这么小的表中选择数据应该不会花很长时间。一定是提取过程花费了这么长时间。您是否存储大数据(图像、视频等)?我假设select count(*) from ParentFormResponses 只需要几秒钟。正确的?至于连接:您提到的 EntityId 和 EntityTypeId 上的索引通常应该很快,至少在有许多不同的 EntityId 时。
    • 另一个问题:估计有多少用户在运行您的查询时访问表 ParentFormResponses?
    • 发布查询计划 .. 还要确保您创建的非聚集索引实际正在使用并且统计信息是最新的..
    • 尝试使用 group by 而不是 distinct

    标签: sql sql-server


    【解决方案1】:

    distinctleft join 的组合从性能角度来看是可疑的。首先,检查以下查询:

    SELECT ECS.UserId, ECS.EntityId
    FROM EventConsentStatus ECS INNER JOIN
         @Institutions I
         ON ECS.InstitutionId = I.InstitutionId             
    WHERE ECS.EventId = @ActivityId;
    

    您可以使用EventConsentStatus(EventId, UserId) 上的索引来优化它。假设这具有良好的性能,它将产生正确的行集。如果没有,那么您可能会从@Institions 获得重复。如果是这种情况,请考虑将其删除(该表中没有使用任何列,它仅用于过滤)。或者:

    SELECT ECS.UserId, ECS.EntityId
    FROM EventConsentStatus ECS 
    WHERE ECS.EventId = @ActivityId AND
          EXISTS (SELECT 1 FROM  @Institutions I WHERE ECS.InstitutionId = I.InstitutionId)
    

    要获得正确的值,让我们使用outer apply 获取附加数据:

    SELECT ECS.UserId, PFR.EntityId, PFR.CreatedBy
    FROM EventConsentStatus ECS INNER JOIN
         @Institutions I
         ON ECS.InstitutionId = I.InstitutionId OUTER APPLY
         (SELECT TOP 1 PFR.EntityId, PFR.CreatedBy
          FROM ParentFormResponses pfr
          WHERE ECS.EventId = PFR.EntityId  AND
                PFR.EntityTypeId = 1 AND
                PFR.EntityId = @ActivityId
         ) pfr
    WHERE ECS.EventId = @ActivityId;
    

    为此,您需要ParentFormResponses(EntityId, EntityTypeID, CreatedBy) 上的索引。

    【讨论】:

    • 我已经尝试使用适当的索引进行外部应用,但仍然花费了太多时间。如果我在 Outer apply 中运行两个查询,另一个分别运行,则只需几秒钟。但是使用左连接或外部应用不会给出优化的结果。
    • @Sakshi 。 . .我刚刚更新了索引定义。我误读了一个相关的join 条件——这会影响索引和性能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-02
    • 2017-12-25
    相关资源
    最近更新 更多