2010-03-30 96 views
8

我有一个查询返回两个数据集之间大量不同的时间量。对于一组(数据库A),它会在几秒内返回,对于另一组(数据库B)....以及我还没有等待足够长的时间,但超过了10分钟。我已经将这两个数据库转储到本地机器,在那里我可以重现运行MySQL 5.1.37的问题。MySQL查询性能 - 时间上的巨大差异

奇怪的是,数据库B小于数据库A较小

甲剥离下来能重现问题查询的版本是:

SELECT * FROM po_shipment ps 
JOIN po_shipment_item psi USING (ship_id) 
JOIN po_alloc pa ON ps.ship_id = pa.ship_id AND pa.UID_items = psi.UID_items 
JOIN po_header ph ON pa.hdr_id = ph.hdr_id 
LEFT JOIN EVENT_TABLE ev0 ON ev0.TABLE_ID1 = ps.ship_id AND ev0.EVENT_TYPE = 'MAS0' 
LEFT JOIN EVENT_TABLE ev1 ON ev1.TABLE_ID1 = ps.ship_id AND ev1.EVENT_TYPE = 'MAS1' 
LEFT JOIN EVENT_TABLE ev2 ON ev2.TABLE_ID1 = ps.ship_id AND ev2.EVENT_TYPE = 'MAS2' 
LEFT JOIN EVENT_TABLE ev3 ON ev3.TABLE_ID1 = ps.ship_id AND ev3.EVENT_TYPE = 'MAS3' 
LEFT JOIN EVENT_TABLE ev4 ON ev4.TABLE_ID1 = ps.ship_id AND ev4.EVENT_TYPE = 'MAS4' 
LEFT JOIN EVENT_TABLE ev5 ON ev5.TABLE_ID1 = ps.ship_id AND ev5.EVENT_TYPE = 'MAS5' 
WHERE ps.eta >= '2010-03-22' 
GROUP BY ps.ship_id 
LIMIT 100; 

第一个数据库的(A)的EXPLAIN查询计划在约2秒的回报是:

+----+-------------+-------+--------+----------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+---------+------------------------------+------+----------------------------------------------+ 
| id | select_type | table | type | possible_keys                               | key        | key_len | ref       | rows | Extra          | 
+----+-------------+-------+--------+----------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+---------+------------------------------+------+----------------------------------------------+ 
| 1 | SIMPLE  | ps | range | PRIMARY,IX_ETA_DATE                             | IX_ETA_DATE      | 4  | NULL       | 174 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE  | ev0 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev1 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev2 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev3 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev4 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev5 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | psi | ref | PRIMARY,IX_po_shipment_item_po_shipment1,FK_po_shipment_item_po_shipment1                | IX_po_shipment_item_po_shipment1 | 4  | UNIVIS_PROD.ps.ship_id  | 1 |            | 
| 1 | SIMPLE  | pa | ref | IX_po_alloc_po_shipment_item2,IX_po_alloc_po_details_old,FK_po_alloc_po_shipment1,FK_po_alloc_po_shipment_item1,FK_po_alloc_po_header1 | FK_po_alloc_po_shipment1   | 4  | UNIVIS_PROD.psi.ship_id  | 5 | Using where         | 
| 1 | SIMPLE  | ph | eq_ref | PRIMARY,IX_HDR_ID                              | PRIMARY       | 4  | UNIVIS_PROD.pa.hdr_id  | 1 |            | 
+----+-------------+-------+--------+----------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+---------+------------------------------+------+----------------------------------------------+ 

的EXPLAIN查询计划,在>600秒返回第二数据库(B)是:

+----+-------------+-------+--------+----------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+---------+--------------------------------+------+----------------------------------------------+ 
| id | select_type | table | type | possible_keys                               | key        | key_len | ref       | rows | Extra          | 
+----+-------------+-------+--------+----------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+---------+--------------------------------+------+----------------------------------------------+ 
| 1 | SIMPLE  | ps | range | PRIMARY,IX_ETA_DATE                             | IX_ETA_DATE      | 4  | NULL       | 38 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE  | psi | ref | PRIMARY,IX_po_shipment_item_po_shipment1,FK_po_shipment_item_po_shipment1                | IX_po_shipment_item_po_shipment1 | 4  | UNIVIS_DEV01.ps.ship_id  | 1 |            | 
| 1 | SIMPLE  | ev0 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_DEV01.psi.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev1 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_DEV01.psi.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev2 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_DEV01.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev3 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_DEV01.psi.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev4 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_DEV01.psi.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev5 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_DEV01.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | pa | ref | IX_po_alloc_po_shipment_item2,IX_po_alloc_po_details_old,FK_po_alloc_po_shipment1,FK_po_alloc_po_shipment_item1,FK_po_alloc_po_header1 | IX_po_alloc_po_shipment_item2 | 4  | UNIVIS_DEV01.ps.ship_id  | 4 | Using where         | 
| 1 | SIMPLE  | ph | eq_ref | PRIMARY,IX_HDR_ID                              | PRIMARY       | 4  | UNIVIS_DEV01.pa.hdr_id   | 1 |            | 
+----+-------------+-------+--------+----------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+---------+--------------------------------+------+----------------------------------------------+ 

当数据库B正在运行时,我可以看看MySQL管理员,并且状态保留在无限期地“复制到tmp表”中。数据库A也有这种状态,但只有一秒左右。

这些数据库之间的表结构,索引,键等没有区别(我已经完成了创建表并将它们区分开来)。

表的尺寸为:

database A: 
po_shipment 1776 
po_shipment_item 1945 
po_alloc 36298 
po_header 71642 
EVENT_TABLE 1608 

database B: 
po_shipment 463 
po_shipment_item 470 
po_alloc 3291 
po_header 56149 
EVENT_TABLE 1089 

几点需要注意:

  • 删除WHERE子句使 查询返回< 1秒。
  • 删除GROUP BY会使查询 返回< 1秒。
  • 删除ev5,ev4,ev3等,使得 查询得到更快的删除每个 。

UPDATE AJ的回答后: - 所述ship_id的大小是在数据库B(最大值= 800002752)比数据库A(最大值= 3489)显著大。鉴于这些InnoDB表将改变任何缓冲区帮助处理这种大小的键? 进一步更新为此:我减少了键的大小和重新分析,但仍然没有改变性能。

UPDATE递减EVENT_TABLE的:

请注意,这是在两个数据库

+--------------------+--------------+------+-----+---------+----------------+ 
| Field    | Type   | Null | Key | Default | Extra   | 
+--------------------+--------------+------+-----+---------+----------------+ 
| EVENT_TABLE_ID  | bigint(20) | NO | PRI | NULL | auto_increment | 
| EVENT_TYPE   | varchar(10) | NO |  | NULL |    | 
| TABLE_ID1   | int(11)  | NO | MUL | NULL |    | 
| TABLE_ID2   | int(11)  | YES |  | NULL |    | 
| TABLE_ID3   | int(11)  | YES |  | NULL |    | 
| TABLE_ID4   | int(11)  | YES |  | NULL |    | 
| EVENT_CREATED_DATE | datetime  | NO |  | NULL |    | 
| MESSAGE_REF  | varchar(100) | YES |  | NULL |    | 
+--------------------+--------------+------+-----+---------+----------------+ 

相同和良好的措施的SHOW CREATE TABLE EVENT_TABLE:

唯一要数据库之间的差异是自动​​增加值

| EVENT_TABLE | CREATE TABLE `EVENT_TABLE` (
    `EVENT_TABLE_ID` bigint(20) NOT NULL AUTO_INCREMENT, 
    `EVENT_TYPE` varchar(10) NOT NULL, 
    `TABLE_ID1` int(11) NOT NULL, 
    `TABLE_ID2` int(11) DEFAULT NULL, 
    `TABLE_ID3` int(11) DEFAULT NULL, 
    `TABLE_ID4` int(11) DEFAULT NULL, 
    `EVENT_CREATED_DATE` datetime NOT NULL, 
    `MESSAGE_REF` varchar(100) DEFAULT NULL, 
    PRIMARY KEY (`EVENT_TABLE_ID`), 
    KEY `IX_EVENT_ID_EVENT_TYPE` (`TABLE_ID1`,`EVENT_TYPE`) 
) ENGINE=InnoDB AUTO_INCREMENT=1925 DEFAULT CHARSET=utf8 | 

任何人都可以建议如何解决这个问题?我错过了什么?

Michael Holzmann问题后的更新 以下是基于他更新的STRAIGHT_JOIN查询的新查询计划。请注意,数据库B有“Using temporary; Using filesort”,而现在数据库A没有。这可能是由于长键或类似的东西?

数据库中的

+----+-------------+-------+--------+----------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+---------+------------------------------+------+-------------+ 
| id | select_type | table | type | possible_keys                               | key        | key_len | ref       | rows | Extra  | 
+----+-------------+-------+--------+----------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+---------+------------------------------+------+-------------+ 
| 1 | SIMPLE  | ps | index | PRIMARY,IX_ETA_DATE                             | PRIMARY       | 4  | NULL       | 168 | Using where | 
| 1 | SIMPLE  | ev0 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |    | 
| 1 | SIMPLE  | ev1 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |    | 
| 1 | SIMPLE  | ev2 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |    | 
| 1 | SIMPLE  | ev3 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |    | 
| 1 | SIMPLE  | ev4 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |    | 
| 1 | SIMPLE  | ev5 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |    | 
| 1 | SIMPLE  | psi | ref | PRIMARY,IX_po_shipment_item_po_shipment1,FK_po_shipment_item_po_shipment1                | IX_po_shipment_item_po_shipment1 | 4  | UNIVIS_PROD.ps.ship_id  | 1 |    | 
| 1 | SIMPLE  | pa | ref | IX_po_alloc_po_shipment_item2,IX_po_alloc_po_details_old,FK_po_alloc_po_shipment1,FK_po_alloc_po_shipment_item1,FK_po_alloc_po_header1 | FK_po_alloc_po_shipment_item1 | 8  | UNIVIS_PROD.psi.UID_items | 6 | Using where | 
| 1 | SIMPLE  | ph | eq_ref | PRIMARY,IX_HDR_ID                              | PRIMARY       | 4  | UNIVIS_PROD.pa.hdr_id  | 1 |    | 
+----+-------------+-------+--------+----------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+---------+------------------------------+------+-------------+ 

数据库B

+----+-------------+-------+--------+----------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+---------+-------------------------------+------+----------------------------------------------+ 
| id | select_type | table | type | possible_keys                               | key        | key_len | ref       | rows | Extra          | 
+----+-------------+-------+--------+----------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+---------+-------------------------------+------+----------------------------------------------+ 
| 1 | SIMPLE  | ps | range | PRIMARY,IX_ETA_DATE                             | IX_ETA_DATE      | 4  | NULL       | 38 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE  | ev0 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_DEV01.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev1 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_DEV01.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev2 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_DEV01.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev3 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_DEV01.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev4 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_DEV01.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev5 | ref | IX_EVENT_ID_EVENT_TYPE                             | IX_EVENT_ID_EVENT_TYPE   | 36  | UNIVIS_DEV01.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | psi | ref | PRIMARY,IX_po_shipment_item_po_shipment1,FK_po_shipment_item_po_shipment1                | IX_po_shipment_item_po_shipment1 | 4  | UNIVIS_DEV01.ps.ship_id  | 1 |            | 
| 1 | SIMPLE  | pa | ref | IX_po_alloc_po_shipment_item2,IX_po_alloc_po_details_old,FK_po_alloc_po_shipment1,FK_po_alloc_po_shipment_item1,FK_po_alloc_po_header1 | IX_po_alloc_po_shipment_item2 | 4  | UNIVIS_DEV01.ps.ship_id  | 3 | Using where         | 
| 1 | SIMPLE  | ph | eq_ref | PRIMARY,IX_HDR_ID                              | PRIMARY       | 4  | UNIVIS_DEV01.pa.hdr_id  | 1 |            | 
+----+-------------+-------+--------+----------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+---------+-------------------------------+------+----------------------------------------------+ 

UPDATE这肯定数据有关。我从一个数据库转储的数据,并使用它加载到数据库B:

SELECT * from <table> into outfile <file> 

LOAD DATA INFILE <file> into table <table> 

那么数据库B查询奔驰 - 即。与数据库A一样快。关于如何诊断数据可能出错的任何想法?

UPDATE @newtover: 从数据库答:

+-----------------+---------------------+ 
| eta_selectivity | ship_id_selectivity | 
+-----------------+---------------------+ 
|   0.0693 |    1.0000 | 
+-----------------+---------------------+ 
1 row in set (0.02 sec) 

从数据库B(坏的)

+-----------------+---------------------+ 
| eta_selectivity | ship_id_selectivity | 
+-----------------+---------------------+ 
|   0.1814 |    1.0000 | 
+-----------------+---------------------+ 
1 row in set (0.02 sec) 

而这次展览会创建po_shipment:

| po_shipment | CREATE TABLE `po_shipment` (
    `ship_id` int(11) NOT NULL DEFAULT '0', 
    `ship_type` varchar(16) DEFAULT NULL, 
    `foreign_agent` varchar(16) DEFAULT NULL, 
    `agent_ref` varchar(16) DEFAULT NULL, 
    `exporter_code` varchar(30) DEFAULT NULL, 
    `importer_code` varchar(30) DEFAULT NULL, 
    `carrier_code` varchar(30) DEFAULT NULL, 
    `exporter_name` varchar(50) DEFAULT NULL, 
    `importer_name` varchar(50) DEFAULT NULL, 
    `carrier_name` varchar(50) DEFAULT NULL, 
    `receipt` varchar(30) DEFAULT NULL, 
    `pol_aol` varchar(50) DEFAULT NULL, 
    `pod_aod` varchar(30) DEFAULT NULL, 
    `final_dest` varchar(50) DEFAULT NULL, 
    `vessel_flno` varchar(30) DEFAULT NULL, 
    `ets` date DEFAULT NULL, 
    `eta` date DEFAULT NULL, 
    `pieces` int(11) DEFAULT '0', 
    `weight` decimal(17,2) DEFAULT '0.00', 
    `volume` decimal(17,2) DEFAULT '0.00', 
    `marks` varchar(500) DEFAULT NULL, 
    `goods_desc` varchar(500) DEFAULT NULL, 
    `ship_terms` varchar(16) DEFAULT NULL, 
    `ship_terms_desc` varchar(50) DEFAULT NULL, 
    `house_hawb` varchar(30) DEFAULT NULL, 
    `ocean_mawb` varchar(30) DEFAULT NULL, 
    `booking_date` date DEFAULT NULL, 
    `expected_cargo` date DEFAULT NULL, 
    `mfrt_jobdisp` varchar(30) DEFAULT NULL, 
    `ship_complete` date DEFAULT NULL, 
    `user_id` varchar(30) DEFAULT NULL, 
    `receipt_desc` varchar(60) DEFAULT NULL, 
    `fin_dest_desc` varchar(60) DEFAULT NULL, 
    `pol_aol_desc` varchar(60) DEFAULT NULL, 
    `pod_aod_desc` varchar(60) DEFAULT NULL, 
    `exporter_ref` varchar(26) DEFAULT NULL, 
    `carrier_ref` varchar(26) DEFAULT NULL, 
    `terms_conds` date DEFAULT NULL, 
    `last_amended` date DEFAULT NULL, 
    `user_amended` varchar(30) DEFAULT NULL, 
    `package_type` varchar(24) DEFAULT NULL, 
    `ext_cancelled` tinyint(1) NOT NULL DEFAULT '0', 
    `ext_goh` tinyint(1) NOT NULL DEFAULT '0', 
    `ext_arrival_date` date DEFAULT NULL, 
    `ext_booking_ref` varchar(255) DEFAULT NULL, 
    `ext_dc_booked_delivery_date` date DEFAULT NULL, 
    `ext_dc_booked_delivery_time` varchar(10) DEFAULT NULL, 
    `ext_comments` text, 
    `deleted` tinyint(1) NOT NULL DEFAULT '0', 
    `last_amended_time` int(10) DEFAULT NULL, 
    `last_amended_uni` varchar(30) DEFAULT NULL, 
    PRIMARY KEY (`ship_id`), 
    KEY `IX_ETA_DATE` (`eta`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 | 

U PDATE @chris_I 如果通过删除EVENT_TABLE以外的所有其他连接来删除查询,我会得到相同的性能(即,蹩脚)

SELECT * FROM po_shipment ps 
LEFT JOIN EVENT_TABLE ev0 ON ev0.TABLE_ID1 = ps.ship_id AND ev0.EVENT_TYPE = 'MAS0' 
LEFT JOIN EVENT_TABLE ev1 ON ev1.TABLE_ID1 = ps.ship_id AND ev1.EVENT_TYPE = 'MAS1' 
LEFT JOIN EVENT_TABLE ev2 ON ev2.TABLE_ID1 = ps.ship_id AND ev2.EVENT_TYPE = 'MAS2' 
LEFT JOIN EVENT_TABLE ev3 ON ev3.TABLE_ID1 = ps.ship_id AND ev3.EVENT_TYPE = 'MAS3' 
LEFT JOIN EVENT_TABLE ev4 ON ev4.TABLE_ID1 = ps.ship_id AND ev4.EVENT_TYPE = 'MAS4' 
LEFT JOIN EVENT_TABLE ev5 ON ev5.TABLE_ID1 = ps.ship_id AND ev5.EVENT_TYPE = 'MAS5' 
WHERE ps.eta >= '2010-03-22' 
GROUP BY ps.ship_id 
LIMIT 100; 

UPDATE @Marcus亚当斯: 查询你已要求与内部连接删除计划:

SELECT * FROM po_shipment ps 
LEFT JOIN EVENT_TABLE ev0 ON ev0.TABLE_ID1 = ps.ship_id AND ev0.EVENT_TYPE = 'MAS0' 
LEFT JOIN EVENT_TABLE ev1 ON ev1.TABLE_ID1 = ps.ship_id AND ev1.EVENT_TYPE = 'MAS1' 
LEFT JOIN EVENT_TABLE ev2 ON ev2.TABLE_ID1 = ps.ship_id AND ev2.EVENT_TYPE = 'MAS2' 
LEFT JOIN EVENT_TABLE ev3 ON ev3.TABLE_ID1 = ps.ship_id AND ev3.EVENT_TYPE = 'MAS3' 
LEFT JOIN EVENT_TABLE ev4 ON ev4.TABLE_ID1 = ps.ship_id AND ev4.EVENT_TYPE = 'MAS4' 
LEFT JOIN EVENT_TABLE ev5 ON ev5.TABLE_ID1 = ps.ship_id AND ev5.EVENT_TYPE = 'MAS5' 
WHERE ps.eta >= '2010-03-22' 
GROUP BY ps.ship_id 
LIMIT 100; 

从数据库查询计划(在0响应。35S)

+----+-------------+-------+-------+------------------------+------------------------+---------+------------------------------+------+----------------------------------------------+ 
| id | select_type | table | type | possible_keys   | key     | key_len | ref       | rows | Extra          | 
+----+-------------+-------+-------+------------------------+------------------------+---------+------------------------------+------+----------------------------------------------+ 
| 1 | SIMPLE  | ps | range | IX_ETA_DATE   | IX_ETA_DATE   | 4  | NULL       | 174 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE  | ev0 | ref | IX_EVENT_ID_EVENT_TYPE | IX_EVENT_ID_EVENT_TYPE | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev1 | ref | IX_EVENT_ID_EVENT_TYPE | IX_EVENT_ID_EVENT_TYPE | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev2 | ref | IX_EVENT_ID_EVENT_TYPE | IX_EVENT_ID_EVENT_TYPE | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev3 | ref | IX_EVENT_ID_EVENT_TYPE | IX_EVENT_ID_EVENT_TYPE | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev4 | ref | IX_EVENT_ID_EVENT_TYPE | IX_EVENT_ID_EVENT_TYPE | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |            | 
| 1 | SIMPLE  | ev5 | ref | IX_EVENT_ID_EVENT_TYPE | IX_EVENT_ID_EVENT_TYPE | 36  | UNIVIS_PROD.ps.ship_id,const | 1 |            | 
+----+-------------+-------+-------+------------------------+------------------------+---------+------------------------------+------+---------------------------------------------- 

查询计划从数据库B(没有及时回应才能使一杯茶)

+----+-------------+-------+-------+------------------------+------------------------+---------+-------------------------------+------+----------------------------------------------+ 
| id | select_type | table | type | possible_keys   | key     | key_len | ref       | rows | Extra          | 
+----+-------------+-------+-------+------------------------+------------------------+---------+-------------------------------+------+----------------------------------------------+ 
| 1 | SIMPLE  | ps | range | IX_ETA_DATE   | IX_ETA_DATE   | 4  | NULL       | 38 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE  | ev0 | ref | IX_EVENT_ID_EVENT_TYPE | IX_EVENT_ID_EVENT_TYPE | 36  
+0

你能否从每个数据库提供'DESCRIBE EVENT_TABLE' ...我很感兴趣的是每个evX连接的解释计划都不一样。 – Dancrumb 2010-03-31 01:41:34

+0

我在回答中加入了一些想法。 – newtover 2010-04-08 08:17:36

+0

如果删除所有连接,absolutley的性能是多少。防爆。 SELECT * FROM po_shipment ps WHERE ps.eta> ='2010-03-22'GROUP BY ps.ship_id LIMIT 100; ? – 2010-04-12 17:10:56

回答

2

指标的。如果它是一个数据问题,我不能告诉你什么确切的问题是,但这里是我最喜欢的解决这类问题的策略:

尝试删除一半的连接。重复递归,直到查询运行速度很快。然后添加在最后一步中删除的一半连接...(此策略将需要比通过连接删除和添加连接少得多的步骤)。

一旦找到“坏”连接,您可以尝试使用额外的“where”子句限制其值,直到查询再次快速运行......在每一步中,总是尝试将问题减半。

注:它可以很好地的情况下,你得到了很多记录你的加入中间结果,即使数据总量是在数据库B小

+0

我已经这样做了。请参阅我的问题中的“注意事项”。删除EVENT_TABLE上的连接可以加快删除每个连接的速度。 – Damo 2010-04-07 21:57:55

+0

@Damo:如果*每个*额外的EVENT_TABLE连接都会导致额外的时间,那么主要问题很可能位于其他连接之一中! EVENT_TABLE然后只是乘以它所花费的时间。 – 2010-04-07 22:45:54

+0

@Chris_I我已经更新了这个问题。我可以删除所有其他连接,只留下EVENT_TABLE并获得相同的效果。 – Damo 2010-04-07 23:22:39

1

更新您的统计资料。有一次我有类似的问题,这对我很有用。

+0

如果您的意思是ANALYZE TABLE,那么我也会这样做,并且我已经为所有涉及这两个数据库的查询的表执行了此操作,但没有任何更改。 – Damo 2010-03-30 23:09:55

2

都没有碰过MySQL的一段时间,但我猜测的问题有做任何

  1. 你检查你的键/连接字段长度(实际数据)可能导致sort_buffer页到磁盘加入大(大)键? (这听起来像是数据问题......)
  2. 服务器设置,基本上是写入内存临时表。几年前我有类似的东西。你是否扩大了key_buffer_size,table_cache,read_rnd_buffer_size,sort_buffer,read_buffer_size以查看是否有帮助?
+0

+1 - 你让我想到这个。更新的问题与关键字 – Damo 2010-03-31 01:20:23

+0

上的一些有趣的信息也闻起来像我的数据问题。试图减少键的大小,并增加缓冲区,但迄今为止没有任何工作。 – Damo 2010-03-31 02:57:25

1

因为它是InnoDB,它看起来很可能是一个锁定问题。还有什么是在同一时间?

+0

什么都没有。这两个数据库已经被拉回到我的开发机器。 – Damo 2010-03-31 04:49:32

3

尝试向查询添加STRAIGHT_JOIN以查看执行计划是否是问题。优化器正在为每个数据库选择不同的执行计划,这可能会导致问题。

SELECT STRAIGHT_JOIN * FROM po_shipment ps 
LEFT JOIN EVENT_TABLE ev0 ON ev0.TABLE_ID1 = ps.ship_id AND ev0.EVENT_TYPE = 'MAS0' 
LEFT JOIN EVENT_TABLE ev1 ON ev1.TABLE_ID1 = ps.ship_id AND ev1.EVENT_TYPE = 'MAS1' 
LEFT JOIN EVENT_TABLE ev2 ON ev2.TABLE_ID1 = ps.ship_id AND ev2.EVENT_TYPE = 'MAS2' 
LEFT JOIN EVENT_TABLE ev3 ON ev3.TABLE_ID1 = ps.ship_id AND ev3.EVENT_TYPE = 'MAS3' 
LEFT JOIN EVENT_TABLE ev4 ON ev4.TABLE_ID1 = ps.ship_id AND ev4.EVENT_TYPE = 'MAS4' 
LEFT JOIN EVENT_TABLE ev5 ON ev5.TABLE_ID1 = ps.ship_id AND ev5.EVENT_TYPE = 'MAS5' 
JOIN po_shipment_item psi USING (ship_id) 
JOIN po_alloc pa ON ps.ship_id = pa.ship_id AND pa.UID_items = psi.UID_items 
JOIN po_header ph ON pa.hdr_id = ph.hdr_id 
WHERE ps.eta >= '2010-03-22' 
GROUP BY ps.ship_id 
LIMIT 100; 

UPDATE
1,因为它使用的主键为数据库中的新的执行计划并不需要一个文件排序或临时表。我将开始在查询中添加USE INDEX以查看是否可以加快对数据库B的查询。ship_id是po_shipment的主键吗?如果是这样,你需要弄清楚什么花费更多的团队或筛选日期。

SELECT STRAIGHT_JOIN * FROM po_shipment ps USE INDEX(PRIMARY) 
LEFT JOIN EVENT_TABLE ev0 ON ev0.TABLE_ID1 = ps.ship_id AND ev0.EVENT_TYPE = 'MAS0' 
LEFT JOIN EVENT_TABLE ev1 ON ev1.TABLE_ID1 = ps.ship_id AND ev1.EVENT_TYPE = 'MAS1' 
LEFT JOIN EVENT_TABLE ev2 ON ev2.TABLE_ID1 = ps.ship_id AND ev2.EVENT_TYPE = 'MAS2' 
LEFT JOIN EVENT_TABLE ev3 ON ev3.TABLE_ID1 = ps.ship_id AND ev3.EVENT_TYPE = 'MAS3' 
LEFT JOIN EVENT_TABLE ev4 ON ev4.TABLE_ID1 = ps.ship_id AND ev4.EVENT_TYPE = 'MAS4' 
LEFT JOIN EVENT_TABLE ev5 ON ev5.TABLE_ID1 = ps.ship_id AND ev5.EVENT_TYPE = 'MAS5' 
JOIN po_shipment_item psi USING (ship_id) 
JOIN po_alloc pa ON ps.ship_id = pa.ship_id AND pa.UID_items = psi.UID_items 
JOIN po_header ph ON pa.hdr_id = ph.hdr_id 
WHERE ps.eta >= '2010-03-22' 
GROUP BY ps.ship_id 
LIMIT 100; 

如果不帮助尝试暗示更多的数据库A的执行计划用于数据库B.

+0

谢谢,有趣的选项。没有改变最终结果。数据库B仍然挂起。查询计划已经改变 - 两者仍然不同。我已经更新了这个问题。 – Damo 2010-03-31 04:56:59

+0

它删除数据库A上的文件和临时表的原因是因为它使用ps的主键。尝试添加USE INDEX,我会在一分钟内添加查询。 – mholzmann 2010-03-31 12:09:41

1

因为它看起来像有些问题与数据有关,找出导致问题的数据可能会有帮助。制作第三个数据库C,并从数据库B中插入一半数据(因此您的行数相同)。如果数据库C比较慢,比不好的数据在那里,否则它在另一半。重复更小和更小的块大小以帮助查找问题数据。

即使数据库B小于数据库A,表'po_header'和'EVENT_TABLE'的比例也不会比较小。这可能与速度差异有关。

+0

+1好方法 – Damo 2010-04-06 21:31:26

0

我想你会以错误的方式去做。当您执行LEFT JOIN时,无论与po_shipment是否匹配,您都会收回EVENT_TABLE中的所有记录。

而且您已经将EVENT_TABLE的LEFT JOIN运行了六次。你回来了(6 *(SELECT count(*)FROM EVENT_TABLE))记录与每个查询。由于分贝比分贝b减少的记录,当然,查询运行的速度更快A.

我觉得像这样将执行世界更好:

DECLARE @TEMP_EVENT_TYPES table 
(
    EVENT_TYPE varchar(10) PRIMARY KEY 
) 
; 
/* 
INSERT VALUES 'MAS0', 'MAS1', 'MAS2', 'MAS3', 'MAS4', 'MAS5' 
*/ 

; 
SELECT * FROM po_shipment ps 
JOIN po_shipment_item psi USING (ship_id) 
JOIN po_alloc pa ON ps.ship_id = pa.ship_id AND pa.UID_items = psi.UID_items 
JOIN po_header ph ON pa.hdr_id = ph.hdr_id 
INNER JOIN 
    EVENT_TABLE et ON et.TABLE_ID1 = ps.ship_id 
INNER JOIN 
    @TEMP_EVENT_TYPES tet ON tet.event_type = et.EVENT_TYPE 
WHERE ps.eta >= '2010-03-22' 
GROUP BY ps.ship_id 
+0

只有当从EVENT_TABLE加入而不是EVENT_TABLE时,才会出现这种情况。他这样做的方式是左连接到EVENT_TABLE,这意味着如果连接失败,那么他仍然会在po_shipment中获得该行的结果。 – Echo 2010-04-06 19:20:32

+0

@Echo:确切地说。即使它没有EVENT_TYPE,我仍然需要该行。 – Damo 2010-04-06 21:32:27

1

不得不试着做“检查表”和/或“OPTIMIZE TABLE”?

我有一个similar situation问题是关键指标哪里没有正确更新和做CHECK TABLE修复它们。远射,但值得尝试。

+0

谢谢。在查询中涉及的所有表上都CHECK TABLE和OPTIMIZE。没有效果。 – Damo 2010-04-07 22:27:36

1

首先确保您已在相应的字段上创建索引。我相信你已经做到了。

接下来,尝试使用索引提示(USE INDEX)强制数据库正确使用索引。

我有一个similar problem其中我认为索引是由mysql正确设置和使用,但他们不是。我能够使用索引提示解决它。

1

什么是po_shipment.eta和po_shipment.ship_id中的数据的选择性。你可以从两个数据库发布下列查询的结果:

SELECT 
    count(distinct eta)/count(*) as eta_selectivity, 
    count(distinct ship_id)/count(*) as ship_id_selectivity 
FROM po_shipment; 

通常更具有选择性的(越接近1),更好的指标是工作现场数据。如果优化器缺少必要的统计信息,原因可能是po_shipment.eta中的数据分布非常不均匀(如果使用'2099-01-01'或类似的值作为特殊值)。

顺便说一句,你能提供SHOW CREATE TABLE po_shipment吗?桌子上的指数可能会有所提示。

UPD:当该字段的选择性低于eta字段时,该索引基本上是无用的。更糟糕的是,它可能会使优化器在选择时感到困惑,并且会降低数据的插入和更新速度。

第一个建议是尝试删除eta字段上的索引并测量结果。可能对于A数据库优化器甚至没有尝试使用索引,因为它的选择性非常低,而对于B数据库,它给了索引一个尝试。

困扰我的第二件事就是为什么你先用ship_id分组?当需要在一个隐式临时表中并且在这些字段之间有一个TEXT(如你的情况)或BLOB一个时,MySQL将总是在磁盘临时表上使用进行排序(这在GROUP BY中是隐含需要的)。在你的情况下,ship_id是聚集的主键,结果无论如何都会按ship_id进行排序。您需要的是提取一个基本查询(如果可能存在多个相应的报告,则已经按ship_id分组),并且使用基本查询来应用您的范围条件并且不使用顶部的组来加入po_shipment。

第三个。当你在顶部使用*时,你是否真的需要所有的字段?加入了10张桌子后,你会收到很多情侣。我几乎不相信你需要他们。即使从结果中排除TEXT字段也可能会提高查询性能。

+0

+1有趣的信息。我已添加要求的数据。 – Damo 2010-04-07 22:09:46

+0

这是一个精简查询来说明问题。 “真正的”查询实际上是一个包含更多连接和一组特定字段而非*的Hibernate查询。话虽如此,我可以放弃GROUP BY。我会检查结果。 – Damo 2010-04-08 20:48:50

1

我在使用范围选择器less than <和greater than>时也遇到同样的情况。

实验:如果范围不是太大,您是否尝试过将范围扩展到IN和IN(...,...,...)语句instad?

E.g

SELECT * FROM po_shipment ps USE INDEX (IX_ETA_DATE) 
JOIN po_shipment_item psi USING (ship_id) 
JOIN po_alloc pa ON ps.ship_id = pa.ship_id AND pa.UID_items = psi.UID_items 
JOIN po_header ph ON pa.hdr_id = ph.hdr_id 
LEFT JOIN EVENT_TABLE ev0 ON ev0.TABLE_ID1 = ps.ship_id AND ev0.EVENT_TYPE = 'MAS0' 
LEFT JOIN EVENT_TABLE ev1 ON ev1.TABLE_ID1 = ps.ship_id AND ev1.EVENT_TYPE = 'MAS1' 
LEFT JOIN EVENT_TABLE ev2 ON ev2.TABLE_ID1 = ps.ship_id AND ev2.EVENT_TYPE = 'MAS2' 
LEFT JOIN EVENT_TABLE ev3 ON ev3.TABLE_ID1 = ps.ship_id AND ev3.EVENT_TYPE = 'MAS3' 
LEFT JOIN EVENT_TABLE ev4 ON ev4.TABLE_ID1 = ps.ship_id AND ev4.EVENT_TYPE = 'MAS4' 
LEFT JOIN EVENT_TABLE ev5 ON ev5.TABLE_ID1 = ps.ship_id AND ev5.EVENT_TYPE = 'MAS5' 
WHERE ps.eta IN ('2010-03-22','2010-03-21','2010-03-20',...) 
GROUP BY ps.ship_id 
LIMIT 100; 

编辑:增值利用INDEX()提示,萨尔曼一个建议。看起来像MySQL看到的可能的指标,但选择不使用它......值得测试。

+0

如果我像这样添加一个IN,它会很快响应。但是,如果我收紧范围条件,则响应速度更快。例如,ps.eta IN('2010-03-19','2010-03-20','2010-03-21')以0.14s响应,而ps.eta> ='2010-03-19'和ps .eta <='2010-03-21'的响应时间为0.06秒。不幸的是我需要更大的日期范围。 – Damo 2010-04-12 21:23:37

1

我认为这可能是GROUP BY子句的手动排序(filesort),导致明显的缺陷。

尝试使用SQL_BIG_RESULT提示来查看MySQL是否会改进它的处理GROUP BY的方法。

SELECT SQL_BIG_RESULT * FROM ... 
+0

这非常有趣。以前,当我查看连接的状态时,它总是“复制到tmp表”,现在使用这个提示它是“发送数据”。虽然没有增加表现。只停留在那个状态很长时间。 – Damo 2010-04-12 21:15:59

+0

@Damo - 发送数据 - 这并不意味着查询完成​​?结果大概有多少数据。包括。 100KB,多1MB?你使用什么网络连接,或者它是本地主机?自从你选择了来自大量表格的所有内容(*)之后,才想到。 E.x将缓慢的结果导出到.TXT或.CSV并检查文件大小。 – 2010-04-13 00:55:28

+0

它是本地主机,没有太多的数据(限制100)。没有理由这么长时间发送数据。 – Damo 2010-04-14 08:34:56

0

它确实看起来像是在为每个状态转换为event_table中的事件记录的po_shipment w/event记录建模一个状态机。

你试图用这个查询表达什么业务逻辑?

您应该可以在您的po_shipment中添加一个状态字段来完成此操作,该操作将对event_table中的一系列事件进行汇总和非规格化。

构建用于验证给定记录的所有6个事件的逻辑不应该在数据库中,它应该在您的模型中并且保存在数据库中(模型的经典状态机模式)。

然后它只是从po_shipment中选择,其中state ='MAS5'和eta> date;

+0

当然不是状态机。这只是一个货件,其中包含一些可配置的事件,这些事件按顺序完成。在用户界面中,您可以查看货件数据,然后查看事件的历史记录。 – Damo 2010-04-14 08:38:04

+0

如果你不能完全改变查询的结构,我敢打赌,你可以将它归结为event_table上的单个连接。加入一次,条件为: ... event_type IN('MAS0','MAS1',...'MAS5') – Winfield 2010-04-14 12:30:22

0

出于好奇 - B中的原始数据是否有很多空值?

+0

两个数据库都有很多空值。特别是在加入的EVENT_TABLEs中。 – Damo 2010-04-14 08:35:40