【问题标题】:How to speed up sql queries ? Indexes?如何加快sql查询?索引?
【发布时间】:2013-06-25 14:35:25
【问题描述】:

我有以下数据库结构:

create table Accounting
(
  Channel,
  Account
)

create table ChannelMapper
(
  AccountingChannel,
  ShipmentsMarketPlace,
  ShipmentsChannel
)

create table AccountMapper
(
  AccountingAccount,
  ShipmentsComponent
)

create table Shipments
(
   MarketPlace,
   Component,
   ProductGroup,
   ShipmentChannel,
   Amount
 )

我在这些表上运行以下查询,我正在尝试优化查询以尽可能快地运行:

 select Accounting.Channel, Accounting.Account, Shipments.MarketPlace
 from Accounting join ChannelMapper on Accounting.Channel = ChannelMapper.AccountingChannel

 join AccountMapper on Accounting.Accounting = ChannelMapper.AccountingAccount
 join Shipments on 
 (
     ChannelMapper.ShipmentsMarketPlace = Shipments.MarketPlace
     and ChannelMapper.AccountingChannel = Shipments.ShipmentChannel
     and AccountMapper.ShipmentsComponent = Shipments.Component
 )
 join (select Component, sum(amount) from Shipment group by component) as Totals
    on  Shipment.Component = Totals.Component

如何让这个查询尽可能快地运行?我应该使用索引吗?如果是这样,我应该索引哪些表的哪些列?

这是我的查询计划的图片:

谢谢,

【问题讨论】:

  • 索引是必不可少的。 WHERE 子句中的任何内容都是索引的候选对象。您可以发布实际架构而不是您的抽象版本吗?
  • 数据建模至关重要。首先:将一些真实类型(可能是域)添加到您的列中。第二:PK/FK 约束是基本的。第三:(根据经验)如果表似乎有两个以上的候选键,它们是可疑的。您的 channelmapper 和 shipping 表可能存在这种现象(可能是 BCNF 或 4NF 违规),但您没有显示任何候选键,甚至语义也很模糊。

标签: mysql sql database optimization


【解决方案1】:

其他三个答案似乎涵盖了索引,因此这是对索引的补充。您没有 where 子句,这意味着您始终选择整个该死的数据库。事实上,您的数据库设计在这方面没有任何用处,例如发货日期。考虑一下。

你也有这个:

join (select Component, sum(amount) from Shipment group by component) as Totals
on  Shipment.Component = Totals.Component

这一切都很好,但是您没有从这个子查询中选择任何内容。因此,你为什么拥有它?如果您确实想选择某些内容,例如 sum(amount),则必须为其提供别名以使其在 select 子句中可用。

【讨论】:

    【解决方案2】:

    索引对于任何数据库都是必不可少的。

    用“外行”的话来说,索引是……嗯,正是如此。您可以将索引视为第二个隐藏的表,它存储两件事:排序后的数据和指向其在表中位置的指针。

    创建索引的一些经验法则:

    1. 为连接中正在(或将要)使用的每个字段创建索引。
    2. 为每个要执行频繁where 条件的字段创建索引。
    3. 避免在所有内容上创建索引。为每个表的相关字段创建索引,并使用关系检索所需的数据。
    4. 避免在double 字段上创建索引,除非绝对必要。
    5. 避免在varchar 字段上创建索引,除非绝对必要。

    我建议您阅读以下内容:http://dev.mysql.com/doc/refman/5.5/en/using-explain.html

    【讨论】:

    • 双精度和 varchar 上的索引在相关时很好。我们是在 2013 年,而不是 1980 年代。
    • @Denis 说得好。我避免使用它们,因为我通常能够使用其他索引字段并获得相同的结果。 (顺便说一句,我不是那么老;-))
    【解决方案3】:

    您的 JOINS 应该是第一个查看的位置。两个最明显的索引候选者是AccountMapper.AccountingAccountChannelMapper.AccountingChannel

    您也应该考虑将Shipments.MarketPlaceShipments.ShipmentChannelShipments.Component 编入索引。

    但是,添加索引会增加维护它们的工作量。虽然它们可能会提高此查询的性能,但您可能会发现更新表变得慢得令人无法接受。在任何情况下,MySQL 优化器都可能决定全表扫描比通过索引访问它更快。

    真正做到这一点的唯一方法是设置似乎可以为您提供最佳结果的索引,然后对系统进行基准测试,以确保您在此处获得所需的结果,同时不影响其他地方的性能。充分利用EXPLAIN 语句来了解发生了什么,并记住您自己或优化器对小表所做的优化可能与您在大表上需要的优化不同。

    【讨论】:

      猜你喜欢
      • 2021-01-31
      • 2013-08-19
      • 1970-01-01
      • 2013-08-28
      • 2014-02-13
      • 1970-01-01
      • 2016-10-30
      • 2015-04-07
      • 1970-01-01
      相关资源
      最近更新 更多