MySQL:这个Join查询可以优化吗?

时间:2012-10-08 10:54:52

标签: mysql query-optimization

我有两张桌子。这些表的create命令如下

CREATE TABLE `invoice` (
  `Id` bigint(20) NOT NULL,
  `VersionNumber` int(11) NOT NULL,
  `CreationDate` datetime default NULL,
  `ModificationDate` datetime default NULL,
  `CreateBy` bigint(20) default NULL,
  `ModifyBy` bigint(20) default NULL,
  `BusinessId` varchar(255) character set utf8 default NULL,
  `Status` int(11) default NULL,
  `VendorId` bigint(20) default NULL,
  `CustomerId` bigint(20) default NULL,
  `OrderDate` date default NULL,
  `ExpectedDate` date default NULL,
  `DeliveryDate` date default NULL,
  `InvoiceFor` int(11) default NULL,
  `Reference` varchar(255) character set utf8 default NULL,
  `Agent` varchar(255) character set utf8 default NULL,
  `BnAgent` varchar(255) character set utf8 default NULL,
  `Note` varchar(255) character set utf8 default NULL,
  `HasVoucher` char(1) character set utf8 default NULL,
  PRIMARY KEY  (`Id`),
  KEY `CustomerId` (`CustomerId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE `invoiceitem` (
  `Id` bigint(20) NOT NULL,
  `VersionNumber` int(11) NOT NULL,
  `CreationDate` datetime default NULL,
  `ModificationDate` datetime default NULL,
  `CreateBy` bigint(20) default NULL,
  `ModifyBy` bigint(20) default NULL,
  `BusinessId` varchar(255) default NULL,
  `Status` int(11) default NULL,
  `InvoiceId` bigint(20) default NULL,
  `ProductId` bigint(20) default NULL,
  `PackageQty` decimal(19,5) default NULL,
  `PackagePrice` decimal(19,5) default NULL,
  `ItemPerPackage` decimal(19,5) default NULL,
  `ItemQty` decimal(19,5) default NULL,
  `ItemPrice` decimal(19,5) default NULL,
  `StoreQty` decimal(19,5) default NULL,
  `RevenuePercent` decimal(19,5) default NULL,
  `PurchasePrice` decimal(19,5) default NULL,
  `Vat` decimal(19,5) default NULL,
  `TotalAmount` decimal(19,5) default NULL,
  `InvoiceItemFor` int(11) default NULL,
  `LifeTimeUptoDate` datetime default NULL,
  PRIMARY KEY  (`Id`),
  KEY `invoiceid_productid` (`InvoiceId`,`ProductId`),
  KEY `ProductId` (`ProductId`),
  CONSTRAINT `FK_invoiceitem` FOREIGN KEY (`InvoiceId`) REFERENCES `invoice` (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

此查询的目的 我必须向管理员显示发票清单。他需要查看发票日期,发票编号,客户ID,产品ID以及客户是否先前使用该产品。

现在查询

SELECT iv.id, iv.CustomerId, ii.ProductId, MAX(iv2.orderdate) AS PriviousDate
FROM invoice AS iv
INNER JOIN invoice AS iv2 
    ON iv.CustomerId=iv2.CustomerId 
    AND iv.OrderDate>iv2.OrderDate
INNER JOIN invoiceItem AS ii 
    ON iv.id=ii.invoiceId 
INNER JOIN invoiceItem AS ii2 
    ON  iv2.id=ii2.invoiceId 
    AND ii.ProductId=ii2.ProductId
WHERE iv.Status=0 
    AND ii.Status=0 
    AND iv2.Status=0 
    AND ii2.Status=0
GROUP BY ii.ProductId, iv.CustomerId

这里iv.id和ii.id是主键 customerId和Productid字段也是索引 和invoiceId是foreginkey(iv.id = ii.invoiceId)

我在我的MySql服务器(本地)中运行此查询 但大部分时间我都超时了。我该如何优化此查询?

此查询的说明如下: enter image description here

现在我申请

create index invoiceid_productid 
  on invoiceItem(invoiceId, productId)

之后解释结果是 enter image description here

2 个答案:

答案 0 :(得分:0)

查看EXPLAIN结果,问题显然是invoiceItem表。它有200,000行,MySQL没有使用任何索引来访问它。

因此,您应该考虑创建索引以加快对它的访问。

我嘲笑你的桌子:

create table invoice (
  id int auto_increment not null,
  customerid int not null,
  orderdate timestamp not null,
  status int default 0 not null,
  primary key(id)
);
create table invoiceItem (
  id int auto_increment not null,
  invoiceId int not null,
  productId int not null,
  status int default 0 not null,
  primary key (id)
);

我创建了这些索引:

create index invoiceId on invoiceItem(invoiceId);
create index cod on invoice(customerid, orderdate);
create index stat on invoice(status);

My EXPLAIN(在空表上)现在所有表都使用类型ref

你也可以看到这个用于MySQL的tutorial; - )

答案 1 :(得分:0)

这里不多(看看你的索引是什么会有所帮助),但假设发票ID随发票日期而增加......我怀疑这可能会稍快一点:

SELECT iv.id, iv.CustomerId, ii.ProductId, MAX(iv2.orderdate) AS PriviousDate
FROM invoice AS iv
INNER JOIN invoice AS iv2 
   ON iv.CustomerId=iv2.CustomerId 
   AND iv.id>iv2.id
INNER JOIN invoiceItem AS ii 
   ON iv.id=ii.invoiceId 
INNER JOIN invoiceItem AS ii2 
   ON  iv2.id=ii2.invoiceId 
   AND ii.ProductId=ii2.ProductId
   AND ii.invoiceId>ii2.invoiceId
WHERE iv.Status=0 
   AND ii.Status=0 
   AND iv2.Status=0 
   AND ii2.Status=0
GROUP BY ii.ProductId, iv.CustomerId

但是你确实需要在invoiceItem表中使用ProductId,Status和InvoiceId的索引,然后才能更快地发现它。