如何加快SQL查询?指标?

时间:2013-06-27 22:22:36

标签: mysql sql database optimization

我有以下数据库结构:

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

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

以下是我的查询计划图片:

enter image description here

谢谢,

enter image description here

3 个答案:

答案 0 :(得分:24)

索引对任何数据库都至关重要。

用“外行”术语来说,索引是......好吧,恰恰相反。您可以将索引视为存储两件事的第二个隐藏表:排序数据和指向其在表中位置的指针。

创建索引的一些拇指规则:

  1. 在连接中使用(或将要使用)的每个字段上创建索引。
  2. 在要执行频繁where条件的每个字段上创建索引。
  3. 避免在所有内容上创建索引。在每个表的相关字段上创建索引,并使用关系来检索所需的数据。
  4. 避免在double字段上创建索引,除非绝对必要。
  5. 避免在varchar字段上创建索引,除非绝对必要。
  6. 我建议你阅读:http://dev.mysql.com/doc/refman/5.5/en/using-explain.html

答案 1 :(得分:3)

你的JOINS应该是第一个看的地方。索引的两个最明显的候选者是AccountMapper.AccountingAccountChannelMapper.AccountingChannel

您还应该考虑为Shipments.MarketPlaceShipments.ShipmentChannelShipments.Component编制索引。

但是,添加索引会增加维护它们的工作量。虽然它们可能会对此查询提供性能提升,但您可能会发现更新表变得非常缓慢。在任何情况下,MySQL优化器可能会决定对表的完整扫描比通过索引访问它更快。

实际上,唯一的方法是设置似乎能给你最好结果的索引,然后对系统进行基准测试,以确保你在这里得到你想要的结果,同时不影响其他地方的性能。充分利用EXPLAIN语句来了解正在发生的事情,并记住您自己或优化器在小表上进行的优化可能与您在较大表上所需的优化不同。

答案 2 :(得分:2)

其他三个答案似乎涵盖了索引,所以这是索引的补充。你没有where子句,这意味着你总是选择整个数据库。实际上,您的数据库设计在这方面没有任何用处,例如发货日期。想一想。

你也有这个:

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

这一切都很好但你没有从这个子查询中选择任何东西。那为什么你呢?如果你确实想要选择一些东西,比如总和(金额),你必须给它一个别名,使其在select子句中可用。