我不确定如何提高此查询的性能。这需要100多秒。我已经添加了索引并尝试了子查询,但似乎没有什么可以提高性能。
查询
SELECT
GiftVoucher.VoucherNumber,
GiftVoucher.DateIssued,
GiftVoucher.DateRedeemed,
R.old_name as RedeemedBy,
I.old_name as IssuedBy,
RH.Name as RedeemedForHotel,
V.old_name as VoidedBy,
GiftVoucher.VoidedReplacment,
GiftVoucher.VoidedDescription
FROM GiftVoucher
LEFT JOIN StaffToWp R ON GiftVoucher.RedeemedBy=R.old_id
LEFT JOIN StaffToWp I ON GiftVoucher.IssuedBy=I.old_id
LEFT JOIN StaffToWp V ON GiftVoucher.VoidedBy=V.old_id
LEFT JOIN Hotel RH ON GiftVoucher.RedeemedForHotelID=RH.HotelID
WHERE DateIssued > "2011-12-31 23:59:59"
LIMIT 0, 20000
GiftVoucher结构
GiftVoucher
Column Type Null Default Comments
GiftVoucherID int(11) No
ParentGiftVoucherID int(11) Yes NULL
Value decimal(19,4) No
VoucherNumber varchar(150) Yes NULL
SendToRecipientAddress int(11) No
DateIssued datetime No
DateRedeemed datetime Yes NULL
GiftVoucherPurchaseID int(11) No
RedeemedBy int(11) Yes NULL
IssuedBy int(11) Yes NULL
Active int(11) No
RedeemedForHotelID int(11) Yes NULL
RedeemedTo int(11) Yes NULL
Redeemed int(1) No 0
RedeemedAmount decimal(19,4) Yes NULL
Voided int(1) No 0
VoidedDate datetime Yes NULL
VoidedBy int(11) Yes NULL
VoidedReplacment int(11) Yes NULL
VoidedDescription mediumtext Yes NULL
SystemVersion int(11) No
Indexes
Keyname Type Unique Packed Column Cardinality Collation Null Comment
PRIMARY BTREE Yes No GiftVoucherID 23191 A No
VoidedBy BTREE No No VoidedBy 2 A Yes
RedeemedBy BTREE No No RedeemedBy 244 A Yes
IssuedBy BTREE No No IssuedBy 212 A Yes
DateIssued BTREE No No DateIssued 23191 A No
RedeemedForHotelID BTREE No No RedeemedForHotelID 10 A Yes
StaffToWP结构
StaffToWp
Column Type Null Default Comments
id int(11) No
old_id int(11) No
old_name varchar(255) No
new_id int(11) No
new_name varchar(255) No
Indexes
Keyname Type Unique Packed Column Cardinality Collation Null Comment
PRIMARY BTREE Yes No id 121 A No
old_id BTREE No No old_id 121 A No
Space usage:
Data 4,524 B
Index 7,168 B
Total 11,692 B
Row Statistics:
Format dynamic
Rows 121
Row length ø 37
Row size ø 97 B
Next autoindex 122
Creation Sep 16, 2015 at 12:01 PM
Last update Sep 16, 2015 at 12:01 PM
Last check Sep 16, 2015 at 12:01 PM
酒店结构
Hotel
Column Type Null Default Comments
HotelID int(11) No
Name varchar(250) No
Telephone varchar(50) No
AccommodationUrl varchar(250) No ''
ColourClass varchar(50) Yes NULL
Indexes
Keyname Type Unique Packed Column Cardinality Collation Null Comment
PRIMARY BTREE Yes No HotelID 7 A No
HotelID BTREE No No HotelID 7 A No
EXPLAIN结果
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE GiftVoucher ALL DateIssued NULL NULL NULL 22180 Using where
1 SIMPLE R ref old_id old_id 4 milsomho_voucher.GiftVoucher.RedeemedBy 1
1 SIMPLE I ref old_id old_id 4 milsomho_voucher.GiftVoucher.IssuedBy 1
1 SIMPLE V ref old_id old_id 4 milsomho_voucher.GiftVoucher.VoidedBy 1
1 SIMPLE RH eq_ref PRIMARY,HotelID PRIMARY 4 milsomho_voucher.GiftVoucher.RedeemedForHotelID 1
答案 0 :(得分:0)
即使您的查询似乎进一步优化,您可以按照下面提到的两种方法进行检查,如果可以减少时间 -
第一种方法:
在GiftVoucher表中创建组合索引而不是单个索引,您必须检查不同的组合,例如在redeemedby,issuedby,voidedby,RedeemedForHotelID,dateissues上的单个组合索引。如果它不起作用,那么尝试使用有限的字段组合,并使用哪种组合可以获得更好的结果。
第二种方法:
当您需要前20,000行然后应用日期范围(下限和上限)时,您可以通过该日期范围确定至少获得20,000行并将其作为子查询,然后使用此子查询应用下一个左连接。这样,mysql必须匹配第一个左表(子查询数据)的有限记录和其他右表。
答案 1 :(得分:0)
实际包括表格结构和解释计划的荣誉!
DateIssued> " 2011-12-31 23:59:59"
据推测,此过滤器会显着减少查询返回的行数。但是你会发现DBMS没有在DateIssued上使用索引:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE GiftVoucher ALL DateIssued NULL NULL NULL 22180 Using where
可能的原因是类型不匹配,迫使MySQL在源表中的每一行上进行类型转换。
尝试:
DateIssued > 20111231235959
您还可以考虑使用其他方法更具体地了解要提取的数据(更多过滤)和对数据进行非规范化,以减少LEFT加入的表的数量。
基数数字看起来相当低 - 这是一个测试数据集吗?它们过时了吗?
答案 2 :(得分:0)
该表有大约22K行?但你要求20K?听起来像LIMIT
是没用的;为什么会这样?
那个日期是4年前......它是否包括GiftVoucher
的大部分内容?如果是这样,DateIssued
上的索引可能不会被使用。这是因为扫描表可能更有效,而不是在索引和数据之间反弹。
综合指数?没有人会帮忙。 DateIssued
,WHERE
和GROUP BY
中只引用了一列ORDER BY
。
old_id
是否在其他表中编入索引?它似乎是(" ref"),但它似乎不是PRIMARY KEY
。
您的LIMIT
没有ORDER BY
。所以你不关心你得到的20K行?
您尚未提供SHOW CREATE TABLE
;我假设引擎是InnoDB?
DateIssued > "2011-12-31 23:59:59"
可用于比较DATETIME
;无需使用不同的语法。
缩小表格大小会有所帮助......你有很多INTs
(带符号,4字节),你可以使用SMALLINT UNSIGNED
(2字节,范围0)。 0.65535)。或MEDIUMINT UNSIGNED
。
有一件事可能会有所帮助...... A"覆盖索引":
INDEX(old_id, old_name)
<{1>} StaffToWp
。这样可以更有效地查找old_id
以获取old_name
,这似乎是LEFT JOINs
中3的目的。