Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
优化慢速SQL查询:派生表和基于行类型的两种不同联接_Sql_Query Optimization_Firebird_Firebird2.1 - Fatal编程技术网

优化慢速SQL查询:派生表和基于行类型的两种不同联接

优化慢速SQL查询:派生表和基于行类型的两种不同联接,sql,query-optimization,firebird,firebird2.1,Sql,Query Optimization,Firebird,Firebird2.1,我用的是火鸟2.1。我想优化以下查询,因为即使在一个小数据集(cca 500记录)上,它的执行速度也非常慢(几乎2秒): 表客户端存储个人和公司/公司组。(ClientType=0人,ClientType=1公司)主键:ClientID 表ClientContacts存储链接到哪些公司的人员:ClientID是公司的ID,ContactClientID是链接到公司的人员的ID。主键:ClientID、ContactClientID 表CompanyGroups存储哪些公司链接到哪些公司组:Par

我用的是火鸟2.1。我想优化以下查询,因为即使在一个小数据集(cca 500记录)上,它的执行速度也非常慢(几乎2秒):

表客户端存储个人和公司/公司组。(ClientType=0人,ClientType=1公司)主键:ClientID

表ClientContacts存储链接到哪些公司的人员:ClientID是公司的ID,ContactClientID是链接到公司的人员的ID。主键:ClientID、ContactClientID

表CompanyGroups存储哪些公司链接到哪些公司组:ParentClientID是公司组的ID,ClientID是附加到公司组的公司ID。主键:ParentClientID,ClientID

因此,一个人可能属于多个公司,一个公司可能属于多个公司集团

我想列出所有的人和公司。对于个人,我想显示它属于哪些公司;对于公司,我想显示该公司属于哪些公司集团

最重要的是,我需要按个人/公司所属的公司/公司组的名称进行搜索。在Firebird中,由于聚合函数“LIST”,我可以通过派生表实现这一点

以下是查询:

SELECT C.ClientID,
  C.ClientType,
  C.ClientName,
  IIF(C.ClientType = 0, PCN.PCompanyNames, CCN.CCompanyNames),
FROM Clients C
  LEFT JOIN (SELECT CC.ContactClientID, LIST(CL.ClientName, ', ') AS PCompanyNames
   FROM ClientContacts CC LEFT JOIN Clients CL ON CL.ClientID = CC.ClientID WHERE 
    CL.AccessRights = 0 OR CL.UserID = :UserID OR (CL.AccessRights = 2 AND 
     CL.ClientID IN (SELECT ClientID FROM ClientRights WHERE UserID = :UserID))
      GROUP BY CC.ContactClientID) PCN ON PCN.ContactClientID = C.ClientID AND C.ClientType = 0
  LEFT JOIN (SELECT CG.ClientID, LIST(CL.ClientName, ', ') AS CCompanyNames
   FROM CompanyGroups CG LEFT JOIN Clients CL ON CL.ClientID = CG.ParentClientID WHERE 
    CL.AccessRights = 0 OR CL.UserID = :UserID OR (CL.AccessRights = 2 AND
     CL.ClientID IN (SELECT ClientID FROM ClientRights WHERE UserID = :UserID))
      GROUP BY CG.ClientID) CCN ON CCN.ClientID = C.ClientID AND C.ClientType = 1
WHERE (C.AccessRights = 0
    OR C.UserID = :UserID
      OR (C.AccessRights = 2 AND C.ClientID IN (SELECT ClientID FROM ClientRights WHERE UserID = :UserID)))
  AND (:SearchStr IS NULL
    OR (PCN.PCompanyNames COLLATE UNICODE_CI LIKE '%' || :SearchStr || '%'
    OR CCN.CCompanyNames COLLATE UNICODE_CI LIKE '%' || :SearchStr || '%'))

更新查询计划,首先是上面的查询,第二个是上面的查询,没有WHERE子句(SELECT中的no)


对不起,我不能发表评论(没有必要的声誉)。没有结构是很难做到的,但我尽力了

因此:

1) 您需要将查询准确地分为两部分:ClientType=0和ClientType=1

2) 您不需要在PCN和CCN中使用左连接,因为这没有意义

3) 您经常使用查询:

select ClientID
from Client
where c.AccessRight = 0 or
      c.UserId = :UserId or
      (c.AccessRight = 2 and
       c.ClientId in (
          select r.ClientId
          from ClientRights r
          where r.UserId = :UserId))
我认为你应该这样做:

with
cl as (
   select c.ClientId, c.ClientName, c.ClientType
   from Client c
   where c.AccessRight = 0 or
         c.UserId = :UserId or
         (c.AccessRight = 2 and c.ClientId in (select r.ClientId from ClientRights r where r.UserId = :UserId))),
q2 as (
    select cc.ContactClientId, List (cl.ClientName, ', ') as PCompanyNames
    from ClientContacts cc
         join cl on (cc.ClientId = cl.ClientId)
    group by cc.ContactClientId),
q3 as (
    select cg.ClientId, List (cl.ClientName, ', ') as CCompanyNames
    from CompanyGroups cg
         join cl on (cg.ParentClientId = cl.ClientId)
    group by cg.ClientId)
select cl.ClientId, cl.ClientType, cl.ClientName, q2.PCompanyNames
from cl
     left join q2 on (cl.ClientId = q2.ContactClientId)
where cl.ClientType = 0
  and (q2.PCompanyNames like '%' || Coalesce (:SearchStr, '') || '%' or Coalesce(:SearchStr, '') = '')
union all
select cl.ClientId, cl.ClientType, cl.ClientName, q3.CCompanyNames
from cl
     left join q3 on (cl.ClientId = q3.ClientId)
where cl.ClientType = 1
  and (q3.CCompanyNames like '%' || Coalesce (:SearchStr, '') || '%' or Coalesce(:SearchStr, '') = '')

对不起,我不能发表评论(没有必要的声誉)。没有结构是很难做到的,但我尽力了

因此:

1) 您需要将查询准确地分为两部分:ClientType=0和ClientType=1

2) 您不需要在PCN和CCN中使用左连接,因为这没有意义

3) 您经常使用查询:

select ClientID
from Client
where c.AccessRight = 0 or
      c.UserId = :UserId or
      (c.AccessRight = 2 and
       c.ClientId in (
          select r.ClientId
          from ClientRights r
          where r.UserId = :UserId))
我认为你应该这样做:

with
cl as (
   select c.ClientId, c.ClientName, c.ClientType
   from Client c
   where c.AccessRight = 0 or
         c.UserId = :UserId or
         (c.AccessRight = 2 and c.ClientId in (select r.ClientId from ClientRights r where r.UserId = :UserId))),
q2 as (
    select cc.ContactClientId, List (cl.ClientName, ', ') as PCompanyNames
    from ClientContacts cc
         join cl on (cc.ClientId = cl.ClientId)
    group by cc.ContactClientId),
q3 as (
    select cg.ClientId, List (cl.ClientName, ', ') as CCompanyNames
    from CompanyGroups cg
         join cl on (cg.ParentClientId = cl.ClientId)
    group by cg.ClientId)
select cl.ClientId, cl.ClientType, cl.ClientName, q2.PCompanyNames
from cl
     left join q2 on (cl.ClientId = q2.ContactClientId)
where cl.ClientType = 0
  and (q2.PCompanyNames like '%' || Coalesce (:SearchStr, '') || '%' or Coalesce(:SearchStr, '') = '')
union all
select cl.ClientId, cl.ClientType, cl.ClientName, q3.CCompanyNames
from cl
     left join q3 on (cl.ClientId = q3.ClientId)
where cl.ClientType = 1
  and (q3.CCompanyNames like '%' || Coalesce (:SearchStr, '') || '%' or Coalesce(:SearchStr, '') = '')

请显示相关表的DDL,包括所有索引。同时发布查询的当前计划。立即跳出的事情之一是在(select…中使用
,用
exists
查询替换它通常会执行得更好。但是性能杀手可能是使用
LIKE
在文本字段内搜索。标记,去掉“IN(SELECT)”和“LIKE”并不能提高性能(正如我用SearchStr=NULL测试的那样,客户端中几乎所有地方的AccessRights都是0)。我会发布更多。好的,我已经添加了查询计划,加上主键,没有其他使用的标记。我建议您也在firebird支持邮件列表上问这个问题。它可能会得到更好的响应。请显示相关表的DDL,包括所有索引。同时发布查询的当前计划。立即跳出的事情之一是在(select…
中使用
,用
exists
查询替换它通常会执行得更好。但是性能杀手可能是使用
LIKE
在文本字段内搜索。标记,去掉“IN(SELECT)”和“LIKE”并不能提高性能(正如我用SearchStr=NULL测试的那样,客户端中几乎所有地方的AccessRights都是0)。我会发布更多。好的,我已经添加了查询计划,加上主键,没有其他使用的标记。我建议您也在firebird支持邮件列表上问这个问题。它可能会得到更好的响应。谢谢,您的查询速度非常快,执行时间不到0.2秒!唯一的问题是,我需要按Clientname对结果集进行排序。在查询中放入ORDERBY子句会将执行时间降低到4秒。在我的查询中,如果按顺序输入,则执行时间相同。关于如何使用ORDERBY子句优化查询,您有什么想法吗?您能按ClientName创建索引吗?在这里写下计时。索引不会更快,同样大约4秒。还有其他想法吗?谢谢,您的查询速度非常快,执行时间不到0.2秒!唯一的问题是,我需要按Clientname对结果集进行排序。在查询中放入ORDERBY子句会将执行时间降低到4秒。在我的查询中,如果按顺序输入,则执行时间相同。关于如何使用ORDERBY子句优化查询,您有什么想法吗?您能按ClientName创建索引吗?在这里写下计时。索引不会更快,同样大约4秒。还有其他想法吗?