如何加速3个连接表中的选择

时间:2014-12-28 05:12:44

标签: c# mysql wpf outer-join mysql-slow-query-log

SELECT it.uid,it.Name,COALESCE(sum(i.Qty),0)-COALESCE(sum(s.Qty),0) as stock
FROM items it
left outer join sales_items s on it.uid=s.ItemID
left outer join inventory i on it.uid=i.uid
group by s.ItemID,i.uid,it.UID;

这是我的查询。此查询需要59秒。如何加快查询速度?


我的桌子 - > 项目

      UID            Item
      5089           JAM100GMXDFRUT
      5090           JAM200GMXDFRUT
      5091           JAM500GMXDFRUT
      5092           JAM800GMXDFRUT

表格 - > sales_items

- slno        ItemID         Item              Qty
- 9           5089           JAM100GMXDFRUT    5
- 10          5090           JAM200GMXDFRUT    2
- 11          5091           JAM500GMXDFRUT    1

表格 - > 库存

- slno         uid            Itemname          Qty
- 102          5089           JAM100GMXDFRUT    10
- 200          5091           JAM500GMXDFRUT    15
- 205          5092           JAM800GMXDFRUT    20

此表有超过6000行

3 个答案:

答案 0 :(得分:0)

将索引放在连接列

sales_items ItemID

库存uid

答案 1 :(得分:0)

如果我正在设计这样的东西,我会有一个看起来像这样的查询和架构。记下我的Idx1索引。我不知道MySql,但是Sql Server会将这些索引用于sum函数,这称为覆盖查询。

select  Item.ItemID, Item.Name, IsNull(sum(inv.Quantity), 0) - IsNull(sum(s.Quantity), 0) as stock
from    Item
Left Join Inventory inv
On      Item.ItemID = inv.ItemID
Left Join Sales s
On      Item.ItemID = s.ItemID
Group by Item.ItemID, Item.Name

Create Table dbo.Location
(
    LocationID int not null identity constraint LocationPK primary key,
    Name NVarChar(256) not null
)

Create Table dbo.Item
(
    ItemID int not null identity constraint ItemPK primary key,
    Name NVarChar(256) not null
);

Create Table dbo.Inventory
(
    InventoryID int not null identity constraint InventoryPK primary key,
    LocationID int not null constraint InventoryLocationFK references dbo.Location(LocationID),
    ItemID int not null constraint InventoryItemFK references dbo.Item(ItemID), 
    Quantity int not null,
    Constraint AK1 Unique(LocationID, ItemID)
);

Create Index InventoryIDX1 on dbo.Inventory(ItemID, Quantity);

Create Table dbo.Sales
(
    SaleID int not null identity constraint SalesPK primary key,
    ItemID int not null constraint SalesItemFK references dbo.Item(ItemID),
    Quantity int not null
);

Create Index SalesIDX1 on dbo.Sales(ItemID, Quantity);

答案 2 :(得分:0)

除了用于优化连接的表上的索引之外,您还使用S.ItemID进行分组而不仅仅使用IT.UID,因为这是连接基础,并且是查询的主FROM表的一部分...如果这是项目表上的可用索引,请使用它,您就完成了。无需通过。

引用组中的sales_items或库存列名称

现在,正如所说的那样,你将遇到的另一个问题就是笛卡尔结果,如果你有相同的“物品ID”的多个记录,你从sales_items和库存中总结,因为我已经非常简化了一个例子,通过

CREATE TABLE items (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(5) NOT NULL,
  PRIMARY KEY (`uid`)
);

CREATE TABLE sales_items (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `itemid` int(11),
  `qty` int(5) NOT NULL,
  PRIMARY KEY (`sid`),
  KEY byItemAndQty (`itemid`,`qty`)
);

CREATE TABLE inventory (
  `iid` int(11) NOT NULL AUTO_INCREMENT,
  `uid` int(11) NOT NULL,
  `qty` int(5) NOT NULL,
  PRIMARY KEY (`iid`),
  KEY byItemAndQty (`itemid`,`qty`)
);

insert into items ( uid, name ) values ( 1, 'test' );

INSERT INTO sales_items ( sid, itemid, qty ) VALUES ( 1, 1, 1 );
INSERT INTO sales_items ( sid, itemid, qty ) VALUES ( 2, 1, 2 );

INSERT INTO inventory ( iid, uid, qty ) VALUES ( 1, 1, 13 );
INSERT INTO inventory ( iid, uid, qty ) VALUES ( 2, 1, 35 );

简单1项, 销售项目2项目1的记录。数量为1和2,总数= 3 第1项的库存2记录.13和35的数量,共计38

SELECT 
      it.uid, 
      it.Name, 
      sum(i.Qty) as iQty,
      sum(s.Qty) as sQty,
      COALESCE( sum(i.Qty),0) - COALESCE(sum(s.Qty),0) as stock 
   FROM 
      items it 
         left outer join sales_items s 
            on it.uid = s.ItemID 
         left outer join inventory i 
            on it.uid = i.uid 
   group by 
      it.uid

因此,您可能希望股票的查询结果为

uid  name   iQty   sQty   stock
1    test   48     3      45
but in reality becomes
1    test   96     6      90

现在......请注意我的假设,但是从这样的多个表中看到类似的sum()s或count()s。我假设ITEMS表是每个项目一个记录 Sales_Items实际上具有比提供的列更多的列(例如销售详细信息和可以跟踪的每个日期/销售计数),并且可以包含给定项目ID的多个销售记录数量(从而匹配我的样本)。最后,Inventory表同样可以每个相同项目有多个记录,例如按日期跟踪的传入库存的购买,以及每个给定项目ID的多个记录(也与我的示例匹配)。

为了防止这种类型的笛卡尔结果,并且还可以提高速度,我会对每个辅助表进行预聚合并加入到该表中。

SELECT 
      it.uid, 
      it.Name, 
      i.iQty,
      s.sQty,
      COALESCE( i.iQty,0) - COALESCE(s.sQty,0) as stock 
   FROM 
      items it 
         left join ( select itemid, sum( qty ) as SQty
                        from sales_items
                        group by itemid ) s
            on it.uid = s.ItemID 
         left join ( select uid, sum( qty ) as IQty
                        from inventory
                        group by uid ) i
            on it.uid = i.uid 
   group by 
      it.uid

你得到正确的

uid  name   iQty   sQty   stock
1    test   48     3      45

是的,这只是针对单个商品ID来证明这一点,但仍然适用于您拥有的库存商品数量以及某些商品可能(或不存在)的相应销售/库存记录。