【问题标题】:Query is very very slow for processing 200000 plus records处理 200000 多条记录的查询非常慢
【发布时间】:2013-03-27 06:54:35
【问题描述】:

Patient & Person 表中有 200,000 行,显示的查询需要 30 秒才能执行。

我已经在PersonIdPerson 表和Patient 表的PatientId 上定义了主键(和聚集索引)。我还能在这里做些什么来提高我的程序的性能?

数据库开发方面的新手。我只知道基本的 SQL。也不确定 SQL Server 能否快速处理 200,000 行。

整个动态过程你可以在https://github.com/Padayappa/SQLProblem/blob/master/Performance看到

有人面对过这样的大行吗?如何在此处提高性能?

DECLARE @return_value int,
        @unitRows bigint,
        @unitPages int,
        @TenantId int,
        @unitItems int,
        @page int   
SET @TenantId = 1
SET @unitItems = 20
SET @page = 1

DECLARE @PatientSearch TABLE(
    [PatientId] [bigint] NOT NULL,
    [PatientIdentifier] [nvarchar](50) NULL,
    [PersonNumber] [nvarchar](20) NULL,
    [FirstName] [nvarchar](100) NOT NULL,
    [LastName] [nvarchar](100) NOT NULL,
    [ResFirstName] [nvarchar](100) NOT NULL,
    [ResLastName] [nvarchar](100) NOT NULL,
    [AddFirstName] [nvarchar](100) NOT NULL,
    [AddLastName] [nvarchar](100) NOT NULL,
    [Address] [nvarchar](255) NULL,
    [City] [nvarchar](50) NULL,
    [State] [nvarchar](50) NULL,
    [ZipCode] [nvarchar](20) NULL,
    [Country] [nvarchar](50) NULL,
    [RowNumber] [bigint] NULL
    ) 

    INSERT INTO @PatientSearch SELECT  PAT.PatientId  
     ,PAT.PatientIdentifier      
     ,PER.PersonNumber  
     ,PER.FirstName  
     ,PER.LastName  
     ,RES_PER.FirstName AS ResFirstName  
     ,RES_PER.LastName AS ResLastName  
     ,ADD_PER.FirstName AS AddFirstName  
     ,ADD_PER.LastName AS AddLastName  
     ,PER.Address  
     ,PER.City  
     ,PER.State  
     ,PER.ZipCode  
     ,PER.Country
     ,ROW_NUMBER() OVER (ORDER BY PAT.PatientId DESC) AS RowNumber 
  FROM  dbo.Patient AS PAT  
  INNER JOIN dbo.Person AS PER  
    ON PAT.PersonId = PER.PersonId  
  INNER JOIN  dbo.Person AS RES_PER  
             ON  PAT.ResponsiblePersonId = RES_PER.PersonId  
  INNER JOIN  dbo.Person AS ADD_PER  
             ON  PAT.AddedBy = ADD_PER.PersonId 
  INNER JOIN dbo.Booking AS B   
             ON PAT.PatientId = B.PatientId 

  WHERE  PAT.TenantId = @TenantId AND B.CategoryId =  @CategoryId 

  GROUP BY PAT.PatientId  
     ,PAT.PatientIdentifier      
     ,PER.PersonNumber  
     ,PER.FirstName  
     ,PER.LastName  
     ,RES_PER.FirstName 
     ,RES_PER.LastName
     ,ADD_PER.FirstName 
     ,ADD_PER.LastName
     ,PER.Address  
     ,PER.City  
     ,PER.State  
     ,PER.ZipCode  
     ,PER.Country      

  ;  

   SELECT @unitRows = @@ROWCOUNT  
     ,@unitPages = (@unitRows / @unitItems) + 1;  

   SELECT *  
   FROM @PatientSearch AS IT  
   WHERE RowNumber BETWEEN (@page - 1) * @unitItems + 1 AND @unitItems * @page  

【问题讨论】:

  • 您在表变量中插入了多少行?您最好创建一个实际的临时表 (#PatientSearch)。原因是查询优化器总是假设一个表变量只有一行(它没有任何统计信息),因此如果你在一个表变量中插入很多行,性能会非常糟糕
  • @marc_s,它实际上为空搜索插入了所有 200000 行:(
  • 为什么您需要将所有 200'000 行复制到临时表中吗?难道你不能在你的实际数据之上定义一个 CTE,然后向它添加 ROW_NUMBER() 函数,然后用它来选择你的数据吗??
  • 顺便说一句:200'000 行无论如何都不是 huge ......如果你说的是 2000 亿行 -那么是的,那将是一个大小适中的数据库。
  • @marc_s, REAL Temp 表意思是CREATE Table #PatientSearch 而不是DECLARE @patientsearch as Table?

标签: sql sql-server sql-server-2008 sql-server-2005 azure-sql-database


【解决方案1】:

好吧,除非我遗漏了某些东西(比如重复的行?),否则您应该可以删除 GROUP BY

GROUP BY PAT.PatientId  
     ,PAT.PatientIdentifier      
     ,PER.PersonNumber  
     ,PER.FirstName  
     ,PER.LastName  
     ,RES_PER.FirstName 
     ,RES_PER.LastName
     ,ADD_PER.FirstName 
     ,ADD_PER.LastName
     ,PER.Address  
     ,PER.City  
     ,PER.State  
     ,PER.ZipCode  
     ,PER.Country      

因为您按选择列表中的所有字段进行分组,并且您按PAT.PatientId 进行分区

此外,您应该在索引包含您加入/过滤的列的表上create index

例如,我将在表 Patient 上创建一个索引,其中包含列 (TenantId、PersonId、ResponsiblePersonId、AddedBy) 和包含的列 (PatientId、PatientIdentifier)

【讨论】:

  • 我有重复的记录,因为患者没有更多的预约。我现在更新了我的查询。它是一个动态搜索查询。请检查
  • CREATE NONCLUSTERED INDEX IX_NC_PatientSearch ON dbo.Patient (TenantId,PersonId,ResponsiblePersonId,AddedBy) INCLUDE (PatientId,PatientIdentifier) 产生相同的结果。现在它又增加了 5 秒 :(
  • 您需要查看执行计划,因为这将使您更好地了解查询正在做什么以及它正在使用哪些索引。看看stackoverflow.com/questions/758912/…codeproject.com/Articles/9990/…。这应该告诉你更多关于表扫描、索引扫描、索引搜索的信息。包含的列、键查找等。
  • 谢谢。我会调查的
【解决方案2】:

坦率地说,200,000 行对 SQL Server 来说不算什么。

请先去掉逻辑冗余,比如你有主键,为什么还要分组这么多列,为什么需要加入同一张表(人)3次?

去除逻辑冗余后,至少需要创建一些复合索引/包含索引。获取执行计划 (CTRL+M) 或 (CTRL+M),看看你错过了什么索引。如果您需要进一步的帮助,请使用几行示例数据粘贴您的表架构。

【讨论】:

  • 1 加入给我患者名字,2 加入给我添加的人名字,第 3 加入给我负责医生名字
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-11
  • 2019-09-06
  • 2018-03-24
  • 1970-01-01
  • 1970-01-01
  • 2018-12-10
相关资源
最近更新 更多