Mysql 索引列上的慢速联接和分组方式

Mysql 索引列上的慢速联接和分组方式,mysql,sql,performance,sql-optimization,Mysql,Sql,Performance,Sql Optimization,以下查询需要15-20秒才能运行 SELECT "Trade_US"."ID" AS "Trade_US.ID", "Server_US"."Name" AS "Server_US.Name", "Trade_US"."TradeTypeID" AS "Trade_US.TradeTypeID", "Users"."ID" AS "Users.ID", "Users"."NickName" AS "Users.NickName", "Item"."ID" AS "Item.ID", "Item"

以下查询需要15-20秒才能运行

SELECT "Trade_US"."ID" AS "Trade_US.ID",
"Server_US"."Name" AS "Server_US.Name",
"Trade_US"."TradeTypeID" AS "Trade_US.TradeTypeID",
"Users"."ID" AS "Users.ID",
"Users"."NickName" AS "Users.NickName",
"Item"."ID" AS "Item.ID",
"Item"."ItemTypeID" AS "Item.ItemTypeID",
"Item"."ItemQualityID" AS "Item.ItemQualityID",
"Item"."Level" AS "Item.Level",
"Item"."IconURL" AS "Item.IconURL",
"Trade_US"."Amount" AS "Trade_US.Amount",
"Trade_US"."BonusPercent" AS "Trade_US.BonusPercent",
"Trade_US"."StartBidTotalSilver" AS "Trade_US.StartBidTotalSilver",
"Trade_US"."BuyOutTotalSilver" AS "Trade_US.BuyOutTotalSilver",
"Trade_US"."Description" AS "Trade_US.Description",
"Trade_US"."LastUpdate" AS "Trade_US.LastUpdate",
"Trade_US"."LastBump" AS "Trade_US.LastBump",
CONCAT(COALESCE("ItemPrefix_Text_EN"."PrefixName",""),"Item_Text_EN"."ItemName") AS "FullItemName",
MAX("TradeOffer_US"."PriceTotalSilver") AS "BestOfferTotalSilver" 
FROM "Trade_US" 
  Inner JOIN "Users" ON (("Trade_US"."TraderUserID" = "Users"."ID"))
  Inner JOIN "Item" ON (("Trade_US"."ItemID" = "Item"."ID"))
  Inner JOIN "Item_Text_EN" ON (("Item"."ID" = "Item_Text_EN"."ItemID"))
  Inner JOIN "Server_US" ON (("Server_US"."ID" = "Trade_US"."GameServerID"))
  Left JOIN "ItemPrefix_Text_EN" ON (("ItemPrefix_Text_EN"."ItemPrefixID" = "Trade_US"."ItemPrefixID"))
  Left JOIN "TradeReply_US" ON (("TradeReply_US"."TradeID" = "Trade_US"."ID"))
  Left JOIN "TradeOffer_US" ON (("TradeOffer_US"."ReplyID" = "TradeReply_US"."ID"))
 GROUP BY "Trade_US"."ID"
 ORDER BY "Trade_US"."LastBump" desc LIMIT 300000, 10
解释给出了以下结果

以下是表格定义

CREATE TABLE Users(
    ID int primary key,

    NickName nvarchar(50) unique not null
);/*2 rows*/

CREATE TABLE ItemType(
    ID INT primary key,
    Name varchar(50) not null
);/*80 rows*/

CREATE TABLE ItemQuality(
    ID INT primary key,
    Name varchar(50) not null
);/*6 rows*/

CREATE TABLE Item(
    ID INT   primary key AUTO_INCREMENT,
    ItemTypeID int not null,
    `Level` int not null,
    ItemQualityID int not null,
    IconURL varchar(100) not null,

    FOREIGN KEY (ItemTypeID) REFERENCES ItemType(ID),
    FOREIGN KEY (ItemQualityID) REFERENCES ItemQuality(ID)
);/*5k rows*/
CREATE INDEX Level ON Item(Level);

CREATE TABLE Item_Text_EN(
    ItemID int primary key,
    ItemName varchar(50) not null,

    FOREIGN KEY (ItemID) REFERENCES Item (ID)
);/*5k rows*/
CREATE INDEX ItemName ON Item_Text_EN(ItemName);

CREATE TABLE ItemPrefix(
    ID INT PRIMARY KEY AUTO_INCREMENT,
    PrefixTypeID INT not null,

    FOREIGN KEY (PrefixTypeID) REFERENCES ItemPrefixType(ID)
);/*100 rows*/

CREATE TABLE ItemPrefix_Text_EN(
    ItemPrefixID INT PRIMARY KEY,
    PrefixName nvarchar(50) not null,

    FOREIGN KEY (ItemPrefixID) REFERENCES ItemPrefix(ID)
);/*100 rows*/

CREATE TABLE Trade_US(
    ID INT primary key AUTO_INCREMENT,
    GameServerID int not null,
    TradeTypeID int not null,
    TraderUserID int not null,
    ItemID int not null,
    Amount int not null,
    BonusPercent int null,
    ItemPrefixID INT null,
    StartBidTotalSilver int null,
    BuyOutTotalSilver int not null,

    `Description` nvarchar(200) null,
    LastUpdate datetime not null,
    LastBump datetime not null,

    FOREIGN KEY (GameServerID) REFERENCES Server_US(ID),
    FOREIGN KEY (TradeTypeID) REFERENCES TradeType(ID),
    FOREIGN KEY (TraderUserID) REFERENCES Users(ID),
    FOREIGN KEY (ItemPrefixID) REFERENCES ItemPrefix(ID),
    FOREIGN KEY (ItemID) REFERENCES Item(ID),

    CHECK (BonusPercent >=0 ),
    CHECK (Amount > 0 AND Amount < 99999),
    CHECK (StartBidTotalSilver < 100000000 AND StartBidTotalSilver >= 0),
    CHECK (BuyOutTotalSilver < 100000000 AND BuyOutTotalSilver >= 0)
);/*1million duplicated rows*/
CREATE INDEX BonusPercent ON Trade_US (BonusPercent);
CREATE INDEX StartBidTotalSilver ON Trade_US (StartBidTotalSilver);
CREATE INDEX BuyOutTotalSilver ON Trade_US (BuyOutTotalSilver);
CREATE INDEX LastBump ON Trade_US (LastBump);

CREATE TABLE TradeReply_US(
    ID INT primary key NOT NULL AUTO_INCREMENT,
    TradeID int not null,
    ReplyUserID int not null,
    `Message` nvarchar(200) null,
    `Time` datetime not null,

    FOREIGN KEY (ReplyUserID) REFERENCES Users(ID),
    FOREIGN KEY (TradeID) REFERENCES Trade_US (ID) on delete cascade
);/*5 rows*/

CREATE TABLE TradeOffer_US(
    ReplyID int primary key,
    PriceTotalSilver int not null,

    FOREIGN KEY (ReplyID) REFERENCES TradeReply_US (ID) on delete cascade,
    CHECK (PriceTotalSilver < 100000000 AND PriceTotalSilver >= 0)
);/*2 rows*/

CREATE TABLE Server_US(
    ID INT primary key,
    Name varchar(20) not null
);/*3 rows*/
*任何名为ID的列都是主键
*数据库客户端版本:libmysql-mysqlnd 5.0.11-dev-20120503
*现在它没有where子句,但是用户可以选择进行搜索,搜索结果是where子句中包含索引列的任意组合


我试图删除所有GROUPBY子句+max(…),运行大约需要8秒。我在LastBump列上使用了force index,它需要大约6秒的时间才能运行,考虑到所有列都被索引了,而且它只有1m行数据,这段时间太长了。我试着在Trade_US中的所有列上添加compsite索引,这些列将用于加入,但毫无帮助。我擦除了整个数据库,然后重新创建了所有的表,看看这是否是高索引碎片的问题,但仍然没有运气。完全没有想法。。非常感谢您的帮助。

我从您的问题标题中删除了mysql标记。请看这里@草莓贸易报价依赖于贸易回复,这是外国对我们贸易的关键。它被用在Max()@草莓移除组中,大大加快了速度,比如2倍。但是仍然需要很长的时间,我们来看看最大堆表大小和tmp表大小怎么样?例如:设置max_heap_table_size=1024*1024*64;设置tmp_table_size=1024*1024*32;您是在共享主机服务器上的八路连接导致的兆行汇总?您正在使用LIMIT抑制排序结果集的前300千行?恕我直言,对于这个工作量来说,半分钟似乎并不合理。要得到你的十行,需要大量的数据。
17 Init 61 µs 
18 Optimizing 14 µs 
19 Statistics 158 µs 
20 Preparing 41 µs 
21 Creating Tmp Table 165 µs 
22 Executing 2 µs 
23 Copying To Tmp Table 14.2 s 
24 Sorting Result 972.5 ms 
25 Sending Data 1.1 s 
26 End 5 µs