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

标签 mysql reference performance count

我正在使用一个设计不佳的数据库,我无权对其进行重组。在此数据库中,涉及三个表(我们称它们为“companiesA”、“companiesB”和“items”)我需要优化的查询。 'companiesA' 和 'companiesB' 描述公司的方式相同,因为列值相同,但它们代表两个不同的公司组并且具有不同的列名称。本质上,ID 和公司名称列是“companiesA”中的“aID”和“aName”,以及“idBcompaniesB”中的“em>”和“nameB”。 “items”包含一列“companyID”,其中包含来自两个公司表之一的外键值。

我需要优化的查询从两个表的联合中获取一个页面的公司 ID 和名称,按名称列排序,并添加一个列,说明该行的公司是否有任何关联的项目。如果用户在前端请求,此查询还可以按公司名称进行过滤。在目前的状态下,我认为它在 THETA(companies * items) 时间内运行,这太慢了:

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(companies + items) 时间内写这篇文章,但我发现很难弄清楚如何在 MySQL 中这样做.是否可以这样做,最好没有存储函数或过程?如果需要,我可以添加它们,但我很难通过 phpMyAdmin 添加它们,因为服务器的主机只允许该接口(interface)通过 GUI 访问数据库。

最佳答案

在这个解决方案中,我大胆假设每个表中的公司名称都是唯一的,方法是使用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  

关于MySQL:如何在线性时间内确定表A和B中的哪些行被表C中的行引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4599973/

相关文章:

php - 如何在分页结果时让查询转移到后续页面

PHP 时间未按实际时间格式排序

mysql - 在没有 Xcode 的情况下使用 Rails 安装 MySQL

mysql - IP 表 : connexion refused with MySQL (10061)

c# - 在某些地方防止 GC 收集以提高性能

c# - 在 F# 项目中使用 C# 库?

传递给构造函数的临时对象的 C++ 生命周期

reference - 缺少 MSBuild Web 部署的二级二进制引用

javascript - 如何检查哪个资源导致网页加载缓慢

android - 一个大 View 或一系列较小的 View