[英]MySql Query Optimization. Too slow
我正在尝试获取一些数据,但是查询要花5分钟以上的时间(应该快到几毫秒)。
这是桌子
CREATE TABLE IF NOT EXISTS `bookings` (
`bkid`
int(11) NOT NULL AUTO_INCREMENT,
`idBuilding`
int(11) NOT NULL,
`checkinDate`
date NOT NULL,
`baggage_checkin`
int(11) DEFAULT NULL,
`baggage_checkin_check`
tinyint(1) DEFAULT NULL,
`arrivalAtAirportTime`
time DEFAULT NULL,
`returnFlightTime`
time DEFAULT NULL,
`arrivalAtAirportTime_check`
tinyint(1) NOT NULL DEFAULT '0',
`flightNumber`
varchar(50) DEFAULT NULL,
`checkinTime`
time NOT NULL DEFAULT '15:00:00',
`checkoutDate`
date NOT NULL,
`baggage_checkout`
int(11) DEFAULT NULL,
`baggage_checkout_check`
tinyint(1) DEFAULT NULL,
`checkoutTime`
time NOT NULL DEFAULT '12:00:00',
`agency`
varchar(255) NOT NULL,
`distributor`
varchar(255) NOT NULL,
`number`
varchar(255) NOT NULL,
`arrivalby`
varchar(50) DEFAULT NULL,
`adults`
int(3) NOT NULL,
`actualAdults`
int(10) DEFAULT NULL,
`doublebeds`
int(3) DEFAULT NULL,
`children`
int(3) NOT NULL,
`singlebeds`
int(3) DEFAULT NULL,
`price`
decimal(8, 2) NOT NULL,
`received`
decimal(8, 2) NOT NULL DEFAULT '0.00',
`createdBy`
int(11) NOT NULL,
`createdTime`
int(11) NOT NULL,
`modifiedBy`
int(11) NOT NULL,
`modifiedTime`
int(11) NOT NULL,
`notes`
longblob NOT NULL,
`checkinBy`
int(11) NOT NULL,
`checkoutBy`
int(11) NOT NULL,
`keys_number`
int(11) DEFAULT NULL,
`keys_number_kept`
int(11) DEFAULT NULL,
`keys_number_back`
int(11) DEFAULT NULL,
`mobile_wifi`
int(11) DEFAULT NULL,
`mobile_wifi_back`
tinyint(1) NOT NULL DEFAULT '0',
`usb_sticks`
int(11) DEFAULT '0',
`bkstatus`
tinyint(4) NOT NULL,
`status`
int(11) NOT NULL,
`booking_fee`
decimal(8, 2) NOT NULL,
`online_guest`
decimal(10, 2) NOT NULL,
`sales`
decimal(10, 2) NOT NULL,
`sales_vat`
decimal(10, 2) DEFAULT NULL,
`distribution`
decimal(10, 2) NOT NULL,
`host_margin`
decimal(10, 2) NOT NULL,
`cleaning_fee`
decimal(8, 2) NOT NULL,
`taxi_to_office`
int(11) DEFAULT NULL,
`taxi_to_office_check`
varchar(50) DEFAULT NULL,
`taxi_apartment_to_office`
int(11) DEFAULT NULL,
`taxi_apartment_to_office_check`
varchar(50) DEFAULT NULL,
`taxi_to_apartment`
int(11) NOT NULL,
`taxi_to_apartment_check`
varchar(50) DEFAULT NULL,
`taxi_to_airport`
int(11) NOT NULL,
`taxi_to_airport_check`
varchar(50) DEFAULT NULL,
`idOrigBuilding`
int(11) NOT NULL,
`guest_satisfaction`
enum('-1', '0', '1') NOT NULL DEFAULT '0',
`guest_informed_status`
enum('1', '2', '3', '4') NOT NULL DEFAULT '1',
`channel_informed_status`
enum('1', '2', '3', '4') NOT NULL DEFAULT '1',
`mail_sent`
tinyint(1) DEFAULT '0',
`mail_sent_date`
timestamp NULL DEFAULT NULL,
`mail_sent_reminder`
tinyint(1) DEFAULT '0',
`mail_sent_reminder_date`
datetime DEFAULT NULL,
`mail_sent_lastreminder`
tinyint(1) DEFAULT '0',
`mail_sent_lastreminder_date`
datetime DEFAULT NULL,
`DELbirthDate`
date DEFAULT NULL,
`DELcity`
varchar(50) DEFAULT NULL,
`cleaning_percentage`
varchar(50) NOT NULL DEFAULT '0',
`rent_percentage`
varchar(50) NOT NULL DEFAULT '0',
`checkout_percentage`
int(3) NOT NULL DEFAULT '0',
`groupType`
varchar(50) NOT NULL,
`deposit`
double NOT NULL,
`idrefundstatustype`
int(11) NOT NULL,
`prepayment`
decimal(10, 2) NOT NULL,
`distribution_changed`
int(11) NOT NULL,
`checkinDT`
datetime NOT NULL,
`checkoutDT`
datetime NOT NULL,
PRIMARY KEY(`bkid`),
KEY `number` (`number`),
KEY `createdBy` (`createdBy`, `modifiedBy`),
KEY `idBuilding` (`idBuilding`),
KEY `checkinDate` (`checkinDate`),
KEY `checkoutDate` (`checkoutDate`),
KEY `checkinTime` (`checkinTime`),
KEY `checkoutTime` (`checkoutTime`),
KEY `checkinDT` (`checkinDT`, `checkoutDT`)
) ENGINE = MyISAM DEFAULT CHARSET = utf8 AUTO_INCREMENT = 15934;
这是查询
select
concat(bu.streetName,' ',bu.houseNumber) as address,
concat(co.firstName,' ',co.middleName,' ',co.lastName) as ownerName,
a.city as city,
a.area as area,
bu.minGuest as minGuest,
bu.maxGuest as maxGuest,
bu.bedrooms as bedrooms,
bu.bathrooms as bathrooms,
bo.checkinDate as checkinDate,
bo.checkinTime as checkinTime,
bo.checkoutDate as checkoutDate,
bo.checkoutTime as checkoutTime,
concat(ifnull(cg.firstName,''),' ',ifnull(cg.middleName,''),' ',ifnull(cg.lastName,'')) as guestName,
bo.adults as guestsCount,
bo.bkid as bkid,
bo.idBuilding as bid,
bu.price as price,
bu.percentage as isPercent,
bu.isActive as isActive,
ifnull(f.hashname,-1) as iconName,
f.ext as iconExt
from
bookings bo
left join
buildings bu
on
bu.id = bo.idBuilding
left join
items i
on
i.guid = bu.guid
left join
images im
on
im.guid = i.icon
left join
files f
on
f.hashname = im.96_hash
left join
areas a
on
a.id = bu.idArea
left join
booking_participant bp
on
bp.bookings_id = bo.bkid
and
bp.role_id = 2
left join
contacts co
on
co.id = bu.idContactOwner
left join
contacts cg
on
cg.id = bp.contacts_id
left join
bookings nextBo
on
nextBo.idBuilding = bo.idBuilding
and
nextBo.checkinDT >= bo.checkoutDT
left join
jobs nextInspection
on
nextInspection.jobtype = 2
and
nextInspection.endDT < nextBo.checkinDT
and
nextInspection.endDT > bo.checkoutDT
left join
jobs nextCleaning
on
nextCleaning.jobtype = 1
and
nextCleaning.endDT < nextBo.checkinDT
and
nextCleaning.endDT > bo.checkoutDT
where
bo.checkinDT>='2014-07-18 00:00:00'
and
bo.checkinDT<='2014-07-18 23:59:59'
group by
bo.bkid
order by
bo.checkinDate, bo.checkinTIme, bu.streetName, bu.houseNumber, bo.createdTime asc;
这是解释结果:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: bo
type: range
possible_keys: checkinDT
key: checkinDT
key_len: 8
ref: NULL
rows: 40
Extra: Using where; Using temporary; Using filesort
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: bu
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: company.bo.idBuilding
rows: 1
Extra:
*************************** 3. row ***************************
id: 1
select_type: SIMPLE
table: i
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: company.bu.guid
rows: 1
Extra:
*************************** 4. row ***************************
id: 1
select_type: SIMPLE
table: im
type: eq_ref
possible_keys: guid
key: guid
key_len: 8
ref: company.i.icon
rows: 1
Extra:
*************************** 5. row ***************************
id: 1
select_type: SIMPLE
table: f
type: ref
possible_keys: hash
key: hash
key_len: 42
ref: company.im.96_hash
rows: 1
Extra:
*************************** 6. row ***************************
id: 1
select_type: SIMPLE
table: a
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: company.bu.idArea
rows: 1
Extra:
*************************** 7. row ***************************
id: 1
select_type: SIMPLE
table: bp
type: ref
possible_keys: PRIMARY,bookings_id,bookings_id_2
key: bookings_id
key_len: 4
ref: company.bo.bkid
rows: 2
Extra: Using index
*************************** 8. row ***************************
id: 1
select_type: SIMPLE
table: co
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: company.bu.idContactOwner
rows: 1
Extra:
*************************** 9. row ***************************
id: 1
select_type: SIMPLE
table: cg
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: company.bp.contacts_id
rows: 1
Extra:
*************************** 10. row ***************************
id: 1
select_type: SIMPLE
table: nextBo
type: ref
possible_keys: idBuilding,checkinDT
key: idBuilding
key_len: 4
ref: company.bo.idBuilding
rows: 71
Extra:
*************************** 11. row ***************************
id: 1
select_type: SIMPLE
table: nextInspection
type: ref
possible_keys: endDT,jobtype
key: jobtype
key_len: 4
ref: const
rows: 2749
Extra:
*************************** 12. row ***************************
id: 1
select_type: SIMPLE
table: nextCleaning
type: ref
possible_keys: endDT,jobtype
key: jobtype
key_len: 4
ref: const
rows: 16040
Extra:
12 rows in set (0.00 sec)
您可能有一个想法如何加快查询速度?
它将用于从服务器选择预订,因此它应该更快。 对于在1天之内发生的预订,查询要花费5分钟以上的时间,因此对于几天来说,情况甚至更糟。
此命令在0.01秒内执行。
做到这一点,但仍然很慢。
这是优化的输出。
mysql> OPTIMIZE TABLE bookings;
+--------------------------+----------+----------+----------+
| Table | Op | Msg_type | Msg_text |
+--------------------------+----------+----------+----------+
| company.bookings | optimize | status | OK |
+--------------------------+----------+----------+----------+
1 row in set (0.02 sec)
myisamchk的输出
Variables (--variable-name=value)
and boolean options {FALSE|TRUE} Value (after reading options)
--------------------------------- ----------------------------------------
character-sets-dir (No default value)
data-file-length 0
keys-used 18446744073709551615
max-record-length 9223372036854775807
set-auto-increment 0
set-collation (No default value)
sort-records 9
tmpdir (No default value)
key-buffer-size 520192
key-cache-block-size 1024
myisam-block-size 1024
read-buffer-size 262136
write-buffer-size 262136
sort-buffer-size 2097144
myisam-sort-buffer-size 2097144
sort-key-blocks 16
decode-bits 9
ft-min-word-len 4
ft-max-word-len 84
ft-stopword-file (No default value)
stats-method nulls_unequal
没错,添加作业加入后查询开始变慢。 在加入nextBo之前,执行时间为0.01在nextBo加入之后,执行时间为0.1。在第一个作业加入之后,执行时间为几分钟。
我进行了您建议的更改,但仍不快。 这是新的查询
select
concat(bu.streetName,' ',bu.houseNumber) as address,
concat(co.firstName,' ',co.middleName,' ',co.lastName) as ownerName,
a.city as city,
a.area as area,
bu.minGuest as minGuest,
bu.maxGuest as maxGuest,
bu.bedrooms as bedrooms,
bu.bathrooms as bathrooms,
bo.checkinDate as checkinDate,
bo.checkinTime as checkinTime,
bo.checkoutDate as checkoutDate,
bo.checkoutTime as checkoutTime,
concat(ifnull(cg.firstName,''),' ',ifnull(cg.middleName,''),' ',ifnull(cg.lastName,'')) as guestName,
bo.adults as guestsCount,
bo.bkid as bkid,
bo.idBuilding as bid,
bu.price as price,
bu.percentage as isPercent,
bu.isActive as isActive,
ifnull(f.hashname,-1) as iconName,
f.ext as iconExt,
(
select
clnid
from
jobs nextInspection
where
nextInspection.jobtype = 2
and
nextInspection.endDT < nextBo.checkinDT
and
nextInspection.endDT > bo.checkoutDT
order by
nextInspection.endDT asc
limit 1
) as nextInspect,
(
select
clnid
from
jobs nextInspection
where
nextInspection.jobtype = 2
and
nextInspection.endDT < nextBo.checkinDT
and
nextInspection.endDT > bo.checkoutDT
order by
nextInspection.endDT asc
limit 1
) as nextClean
from
bookings bo
left join
buildings bu
on
bu.id = bo.idBuilding
left join
items i
on
i.guid = bu.guid
left join
images im
on
im.guid = i.icon
left join
files f
on
f.hashname = im.96_hash
left join
areas a
on
a.id = bu.idArea
left join
booking_participant bp
on
bp.bookings_id = bo.bkid
and
bp.role_id = 2
left join
contacts co
on
co.id = bu.idContactOwner
left join
contacts cg
on
cg.id = bp.contacts_id
left join
bookings nextBo
on
nextBo.idBuilding = bo.idBuilding
and
nextBo.checkinDT >= bo.checkoutDT
where
bo.checkinDT>='2014-07-18 00:00:00'
and
bo.checkinDT<='2014-07-18 23:59:59'
group by
bo.bkid
order by
bo.checkinDate, bo.checkinTIme, bu.streetName, bu.houseNumber, bo.createdTime asc;
现在的解释说
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: bo
type: range
possible_keys: checkinDT
key: checkinDT
key_len: 8
ref: NULL
rows: 74
Extra: Using where; Using temporary; Using filesort
*************************** 2. row ***************************
id: 1
select_type: PRIMARY
table: bu
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: company.bo.idBuilding
rows: 1
Extra:
*************************** 3. row ***************************
id: 1
select_type: PRIMARY
table: i
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: company.bu.guid
rows: 1
Extra:
*************************** 4. row ***************************
id: 1
select_type: PRIMARY
table: im
type: eq_ref
possible_keys: guid
key: guid
key_len: 8
ref: company.i.icon
rows: 1
Extra:
*************************** 5. row ***************************
id: 1
select_type: PRIMARY
table: f
type: ref
possible_keys: hash
key: hash
key_len: 42
ref: company.im.96_hash
rows: 1
Extra:
*************************** 6. row ***************************
id: 1
select_type: PRIMARY
table: a
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: company.bu.idArea
rows: 1
Extra:
*************************** 7. row ***************************
id: 1
select_type: PRIMARY
table: bp
type: ref
possible_keys: PRIMARY,bookings_id,bookings_id_2
key: bookings_id
key_len: 4
ref: company.bo.bkid
rows: 2
Extra: Using index
*************************** 8. row ***************************
id: 1
select_type: PRIMARY
table: co
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: company.bu.idContactOwner
rows: 1
Extra:
*************************** 9. row ***************************
id: 1
select_type: PRIMARY
table: cg
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: company.bp.contacts_id
rows: 1
Extra:
*************************** 10. row ***************************
id: 1
select_type: PRIMARY
table: nextBo
type: ref
possible_keys: idBuilding,checkinDT
key: idBuilding
key_len: 4
ref: company.bo.idBuilding
rows: 70
Extra:
*************************** 11. row ***************************
id: 3
select_type: DEPENDENT SUBQUERY
table: nextInspection
type: index
possible_keys: endDT,jobtype
key: endDT
key_len: 8
ref: NULL
rows: 10
Extra: Using where
*************************** 12. row ***************************
id: 2
select_type: DEPENDENT SUBQUERY
table: nextInspection
type: index
possible_keys: endDT,jobtype
key: endDT
key_len: 8
ref: NULL
rows: 10
Extra: Using where
12 rows in set (0.00 sec)
实际上,我只是发现我忘记了加入idBuilding上的jobs表,因此它正在获取所有建筑物的工作,而不是仅获取当前建筑物的工作。 无论如何,现在执行时间是1秒而不是5分钟,但是应用程序的响应时间应该比该响应时间要快得多(每天大约0.01秒是可以接受的,因此如果搜索全年,则总共大约3秒)像现在这样5分钟之内..)
这是最新的查询
select
concat(bu.streetName,' ',bu.houseNumber) as address,
concat(co.firstName,' ',co.middleName,' ',co.lastName) as ownerName,
a.city as city,
a.area as area,
bu.minGuest as minGuest,
bu.maxGuest as maxGuest,
bu.bedrooms as bedrooms,
bu.bathrooms as bathrooms,
bo.checkinDate as checkinDate,
bo.checkinTime as checkinTime,
bo.checkoutDate as checkoutDate,
bo.checkoutTime as checkoutTime,
concat(ifnull(cg.firstName,''),' ',ifnull(cg.middleName,''),' ',ifnull(cg.lastName,'')) as guestName,
bo.adults as guestsCount,
bo.bkid as bkid,
bo.idBuilding as bid,
bu.price as price,
bu.percentage as isPercent,
bu.isActive as isActive,
ifnull(f.hashname,-1) as iconName,
f.ext as iconExt,
( select
clnid
from
jobs nextInspection
where
nextInspection.idBuilding = bo.idBuilding
and
nextInspection.jobtype = 2
and
nextInspection.endDT < nextBo.checkinDT
and
nextInspection.endDT > bo.checkoutDT
) as inspectionClnid,
( select
clnid
from
jobs nextCleaning
where
nextCleaning.idBuilding = bo.idBuilding
and
nextCleaning.jobtype = 1
and
nextCleaning.endDT < nextBo.checkinDT
and
nextCleaning.endDT > bo.checkoutDT
) as cleaningClnid
from
bookings bo
left join
buildings bu
on
bu.id = bo.idBuilding
left join
items i
on
i.guid = bu.guid
left join
images im
on
im.guid = i.icon
left join
files f
on
f.hashname = im.96_hash
left join
areas a
on
a.id = bu.idArea
left join
booking_participant bp
on
bp.bookings_id = bo.bkid
and
bp.role_id = 2
left join
contacts co
on
co.id = bu.idContactOwner
left join
contacts cg
on
cg.id = bp.contacts_id
left join
bookings nextBo
on
nextBo.idBuilding = bo.idBuilding
and
nextBo.checkinDT >= bo.checkoutDT
where
bo.checkinDT>='2014-07-18 00:00:00'
and
bo.checkinDT<='2014-07-18 23:59:59'
group by
bo.bkid
order by
bo.checkinDate, bo.checkinTIme, bu.streetName, bu.houseNumber, bo.createdTime asc;
这就是解释结果
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: bo
type: range
possible_keys: checkinDT
key: checkinDT
key_len: 8
ref: NULL
rows: 73
Extra: Using where; Using temporary; Using filesort
*************************** 2. row ***************************
id: 1
select_type: PRIMARY
table: bu
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: company.bo.idBuilding
rows: 1
Extra:
*************************** 3. row ***************************
id: 1
select_type: PRIMARY
table: i
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: company.bu.guid
rows: 1
Extra:
*************************** 4. row ***************************
id: 1
select_type: PRIMARY
table: im
type: eq_ref
possible_keys: guid
key: guid
key_len: 8
ref: company.i.icon
rows: 1
Extra:
*************************** 5. row ***************************
id: 1
select_type: PRIMARY
table: f
type: ref
possible_keys: hash
key: hash
key_len: 42
ref: company.im.96_hash
rows: 1
Extra:
*************************** 6. row ***************************
id: 1
select_type: PRIMARY
table: a
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: company.bu.idArea
rows: 1
Extra:
*************************** 7. row ***************************
id: 1
select_type: PRIMARY
table: bp
type: ref
possible_keys: PRIMARY,bookings_id,bookings_id_2
key: bookings_id
key_len: 4
ref: company.bo.bkid
rows: 2
Extra: Using index
*************************** 8. row ***************************
id: 1
select_type: PRIMARY
table: co
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: company.bu.idContactOwner
rows: 1
Extra:
*************************** 9. row ***************************
id: 1
select_type: PRIMARY
table: cg
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: company.bp.contacts_id
rows: 1
Extra:
*************************** 10. row ***************************
id: 1
select_type: PRIMARY
table: nextBo
type: ref
possible_keys: idBuilding,checkinDT
key: idBuilding
key_len: 4
ref: company.bo.idBuilding
rows: 70
Extra:
*************************** 11. row ***************************
id: 3
select_type: DEPENDENT SUBQUERY
table: nextCleaning
type: ref
possible_keys: idBuilding,endDT,jobtype
key: idBuilding
key_len: 4
ref: func
rows: 128
Extra: Using where
*************************** 12. row ***************************
id: 2
select_type: DEPENDENT SUBQUERY
table: nextInspection
type: ref
possible_keys: idBuilding,endDT,jobtype
key: idBuilding
key_len: 4
ref: func
rows: 128
Extra: Using where
12 rows in set (0.00 sec)
有趣。 实际上, 您的查询看起来不错 ,索引看起来很好,您唯一的WHERE子句变量是bo.checkinDT,该变量已建立索引(尽管只是较大索引的一部分,但它是剩余的一部分...)。
GROUP BY
的目的是什么? 您没有使用任何分组功能。 您是DISTINCT的简写吗?
你能试一下吗:
SELECT * FROM bookings bo where bo.checkinDT>='2014-07-18 00:00:00' and bo.checkinDT<='2014-07-18 23:59:59'
) 。 那也慢吗? 如果不是,则可能是通过玩游戏的联接/组。 bookings.checkinDT
上创建单独的索引? OPTIMIZE TABLE bookings
? myisamchk --sort-index --sort-records=9
(如果9是checkinDT索引)? (当您提供详细信息时,我会更新我的答案)。
好的,因为基本查询(仅针对预订)是快速的,所以联接正在减慢它的速度。 您可以对基表执行SELECT *
,然后一个接一个地添加一个LEFT JOIN吗?
jobs
表(2749行)和(16040行)引起了问题。 我是不是看错了,还是您(当前)甚至没有使用桌子?
如果您所需要的只是两个日期的下一个日期,则子查询可能会更快,您可以尝试将其放入选择语句中:
(SELECT * FROM jobs nextInspection
WHERE nextInspection.jobtype = 2
and nextInspection.endDT < nextBo.checkinDT
and nextInspection.endDT > bo.checkoutDT
ORDER BY nextInspection.endDT ASC
LIMIT 1)
获取当前检出之后但下一次检入之前的第一个“检查”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.