MySQL:如何确定表A中的哪些行在表C中的行以线性时间引用?

时间:2011-01-05 01:03:19

标签: mysql reference performance count

我正在使用一个设计糟糕的数据库,我不能自由重组。在这个数据库中,有三个表(我们称之为' companiesA ',' companiesB '和' items ')我需要优化的查询。 ' companiesA '和' companiesB '以相同的方式描述公司,因为列值相同,但它们代表两个不同的公司组,并且具有不同的列名。基本上,ID和公司名称列在' companiesA '中的' aID '和' aName ',以及' idB em> companiesB '中的em>'和' nameB '。 ' items '包含一个列' companyID ',其中包含来自两个公司表之一的外键值。

我需要优化的查询从两个表的并集中获取页面的公司ID和名称,按名称列排序,并添加一列,说明行的公司是否有与之关联的项目。如果用户在前端请求,则此查询还可以按公司名称进行筛选。在目前的状态下,我认为它运行在THETA(公司*项目)时间,这非常缓慢:

select
  a.aID as companyID,
  a.aName as companyName,
  (select
     count(companyID)
   from
     items
   where
     companyID = a.aID
  ) as items
from
  companiesA as a
where
  a.aName like '%<string>%'

union

select
  b.idB as companyID,
  b.nameB as companyName,
  (select
     count(companyID)
   from
     items
   where
     companyID = b.idB
  ) as items
from
  companiesB as b
where
  b.nameB like '%<string>%'

order by
  companyName ASC
limit
  [optional_starting_index, ] 50;

在此查询返回时,items列包含实际计数并不重要(这是我能够干净地返回关于整个' items '表的值的唯一方法)。我想幸运的是,我有幸拥有1500家公司和9000个项目,这个算法只需要7秒钟。

如果我用另一种我自己访问表格的语言写这个,我可以轻松地在O(公司+项目)时间写这个,但我发现很难弄清楚如何在MySQL中这样做。是否可以这样做,最好没有存储功能或程序?我可以在必要时添加它们,但是我现在很难通过phpMyAdmin添加它们,因为服务器的主机只允许该接口通过GUI访问数据库。

1 个答案:

答案 0 :(得分:1)

在这个解决方案中,我采用了大胆的假设,即每个表中的公司名称都是唯一的Union All。如果不是,那么您可以切换回Union但是您将获得使列表唯一的性能影响。基本上,我正在消除您对相关子查询的需求,以通过使用派生表来返回计数。

Select Companies.CompanyID, Companies.CompanyName
    , Coalesce(ItemTotals.ItemCount,0) As ItemCount
From    (
        Select a.aID As CompanyID, a.aName As CompanyName
        From companiesA As a
        Where a.aName Like '%<string>%'
        Union All
        Select b.IDB, b.nameB
        From companiesB As b
        Where b.bName Like '%<string>%'
        ) As Companies
    Left Join   (
                Select companyID, Count(*) As ItemCount
                From items
                Group By companyID
                ) As ItemTotals
            On ItemTotals.companyID = Companies.CompanyID
Order By Company.CompanyName

这是另一种变体。除了我用两个Group By查询替换相关子查询之外,这个与原始类似。和以前一样,如果两个表之间的名称和ID是互斥的,则可以使用Union All,否则您将需要使用Union

Select Z.CompanyId, Z.CompanyName, Z.ItemCount
From    (
        Select A.companyID, A.aName As CompanyName
            , Count(I.CompanyID) As ItemCount
        From companiesA As A
            Left Join items As I
                On I.CompanyId = A.CompanyId
        Where A.aName Like '%<string>%'
        Group By A.companyID, A.aName
        Union All
        Select B.companyID, B.bName, Count(I.CompanyID)
        From companiesB As B
            Left Join items As I
                On I.CompanyId = B.CompanyId
        Where B.bName Like '%<string>%'
        Group By B.companyID, B.bName
        ) As Z
Order By Z.CompanyName