Mysql - 执行查询花费太多时间
Mysql - Taking too much time to execute queries
所以首先我的 mysql table 是这样定义的:
订单(333000+条记录)
orders_id(PK),
customerName,
CompanyName,
Status,
shipping_no,
shipping_module,
tracking_no,
orders_status,
date_purchased..
Order_status(70条记录)
orders_status_id(pk),
language_id,
orders_status_name
orders_status_history(2220000+条记录)
`orders_status_history_id` int(11)
`orders_id` int(11)
`orders_status_id` int(5)
PRIMARY KEY (`orders_status_history_id`)
orders_status_history table 包含每个订单的不同状态
`orders_status_id` int(11)
`orders_status_name` varchar(32)
PRIMARY KEY (`orders_status_id`,`language_id`)
所以我想要得到的是下面描述的所有三个选项:
- 订单必须有
shipping_module
pickup_pickup或pickup2_pickup2
orders_status_history.orders_status_id
必须有以下状态 7, 21, 34, 40
- 但是
orders_status_history.orders_status_id
不能有以下状态 33,53
解释问题:
假设有 10 个订单,他们在生活中的某个时候有过以下状态:
- [7, 34, 41,48]
- [20, 40, 34, 57, 14, 25]
- [53,7,40,5]
- [41,25,4]
- [1,2,3,4]
- [34,4,33,53,7]
- [4,21,31,7,8]
- [78,15,45,40]
- [53,40,31,21,7]
- [33,74,54,7,22]
所以我要提取的订单是 1、2、7、8,因为这些订单包含 7、31、21 或 40 而不是 53、33
我试过以下查询:
1.)
SELECT *
FROM orders AS o, orders_status_history AS osh
WHERE (
o.shipping_module LIKE '%pickup_pickup%'
OR o.shipping_module LIKE '%pickup2_pickup2%'
)
AND o.orders_id = osh.orders_id
AND osh.orders_status_id
IN ( 7, 21, 31, 40 ) AND osh.orders_status_id
NOT IN (33, 53)
此查询性能正常,但它获得了所有结果(1200 条记录)但它没有过滤 3 个选项
2.)
SELECT *
FROM orders AS o, orders_status_history AS osh
WHERE (
o.shipping_module LIKE '%pickup_pickup%'
OR o.shipping_module LIKE '%pickup2_pickup2%'
)
AND o.orders_id = osh.orders_id
AND osh.orders_status_id IN (7, 21, 31, 40)
AND osh.orders_status_id != 33
AND osh.orders_status_id != 53
它也像以前一样工作,没有过滤第三个选项
3.)
SELECT *
FROM orders AS o, orders_status_history AS osh
WHERE (
o.shipping_module LIKE '%pickup_pickup%'
OR o.shipping_module LIKE '%pickup2_pickup2%'
)
AND o.orders_id = osh.orders_id
AND osh.orders_status_id IN (7, 21, 31, 40)
AND osh.orders_status_id NOT IN (
SELECT so.orders_id
FROM orders AS so, orders_status_history AS sosh
WHERE (
so.shipping_module LIKE '%pickup_pickup%'
OR so.shipping_module LIKE '%pickup2_pickup2%'
)
AND sosh.orders_status_id != 33
)
此查询执行时间过长,未能执行
4.)
SELECT *
FROM orders AS o, orders_status_history AS osh
WHERE (
o.shipping_module LIKE '%pickup_pickup%'
OR o.shipping_module LIKE '%pickup2_pickup2%'
)
AND o.orders_id = osh.orders_id
AND osh.orders_status_id = 7
AND osh.orders_status_id = 21
AND osh.orders_status_id = 31
AND osh.orders_status_id = 40
AND osh.orders_status_id != 33
AND osh.orders_status_id != 53
此查询作为第一个查询也没有过滤第三个选项
所以后来我用php
试了一下
$sql = "SELECT o.orders_id, osh.orders_status_history_id
FROM
orders AS o,
orders_status_history AS osh
WHERE (
o.shipping_module LIKE '%pickup_pickup%'
OR o.shipping_module LIKE '%pickup2_pickup2%'
)
AND o.orders_id = osh.orders_id
AND osh.orders_status_id IN (7, 21, 31, 40)
AND osh.orders_status_id != 33
AND osh.orders_status_id != 53";
$sql = mysql_query($sql);
while ($row = mysql_fetch_array($sql)){
$row["orders_id"]);
if(getOrderStatus($row["orders_id"]))
echo "<br/>".$row["orders_id"];
}
function getOrderStatus($order){
$sql = "SELECT orders_status_id FROM orders_status_history WHERE orders_id = ".$order;
echo "<br/> Sql Query : ".$sql;
$sql = mysql_query($sql);
while ($status = mysql_fetch_array($sql))
if((int)$status["orders_status_id"] == 33 || (int)$status["orders_status_id"] == 53)
return false;
return true;
}
此代码花费的时间超过 30 米。我set_time_limit(0);
注意:我只能用Mysql_*因为我们的php版本是4.9
这是获取满足您条件的订单的一种方法:
SELECT o.orders_id
FROM orders o JOIN
orders_status_history osh
ON o.orders_id = osh.orders_id
WHERE (o.shipping_module LIKE '%pickup_pickup%' OR
o.shipping_module LIKE '%pickup2_pickup2%'
) AND
osh.orders_status_id IN (7, 21, 31, 40, 33, 53)
GROUP BY o.orders_id
HAVING SUM( osh.orders_status_id IN (33, 53) ) = 0;
WHERE
只选择您关心的状态。 HAVING
确保您没有最后两个。
如果您想要订单或订单行的详细信息,则需要重新加入这些表。
所以首先我的 mysql table 是这样定义的:
订单(333000+条记录)
orders_id(PK),
customerName,
CompanyName,
Status,
shipping_no,
shipping_module,
tracking_no,
orders_status,
date_purchased..
Order_status(70条记录)
orders_status_id(pk),
language_id,
orders_status_name
orders_status_history(2220000+条记录)
`orders_status_history_id` int(11)
`orders_id` int(11)
`orders_status_id` int(5)
PRIMARY KEY (`orders_status_history_id`)
orders_status_history table 包含每个订单的不同状态
`orders_status_id` int(11)
`orders_status_name` varchar(32)
PRIMARY KEY (`orders_status_id`,`language_id`)
所以我想要得到的是下面描述的所有三个选项:
- 订单必须有
shipping_module
pickup_pickup或pickup2_pickup2 orders_status_history.orders_status_id
必须有以下状态 7, 21, 34, 40- 但是
orders_status_history.orders_status_id
不能有以下状态 33,53
解释问题: 假设有 10 个订单,他们在生活中的某个时候有过以下状态:
- [7, 34, 41,48]
- [20, 40, 34, 57, 14, 25]
- [53,7,40,5]
- [41,25,4]
- [1,2,3,4]
- [34,4,33,53,7]
- [4,21,31,7,8]
- [78,15,45,40]
- [53,40,31,21,7]
- [33,74,54,7,22]
所以我要提取的订单是 1、2、7、8,因为这些订单包含 7、31、21 或 40 而不是 53、33
我试过以下查询:
1.)
SELECT *
FROM orders AS o, orders_status_history AS osh
WHERE (
o.shipping_module LIKE '%pickup_pickup%'
OR o.shipping_module LIKE '%pickup2_pickup2%'
)
AND o.orders_id = osh.orders_id
AND osh.orders_status_id
IN ( 7, 21, 31, 40 ) AND osh.orders_status_id
NOT IN (33, 53)
此查询性能正常,但它获得了所有结果(1200 条记录)但它没有过滤 3 个选项
2.)
SELECT *
FROM orders AS o, orders_status_history AS osh
WHERE (
o.shipping_module LIKE '%pickup_pickup%'
OR o.shipping_module LIKE '%pickup2_pickup2%'
)
AND o.orders_id = osh.orders_id
AND osh.orders_status_id IN (7, 21, 31, 40)
AND osh.orders_status_id != 33
AND osh.orders_status_id != 53
它也像以前一样工作,没有过滤第三个选项
3.)
SELECT *
FROM orders AS o, orders_status_history AS osh
WHERE (
o.shipping_module LIKE '%pickup_pickup%'
OR o.shipping_module LIKE '%pickup2_pickup2%'
)
AND o.orders_id = osh.orders_id
AND osh.orders_status_id IN (7, 21, 31, 40)
AND osh.orders_status_id NOT IN (
SELECT so.orders_id
FROM orders AS so, orders_status_history AS sosh
WHERE (
so.shipping_module LIKE '%pickup_pickup%'
OR so.shipping_module LIKE '%pickup2_pickup2%'
)
AND sosh.orders_status_id != 33
)
此查询执行时间过长,未能执行
4.)
SELECT *
FROM orders AS o, orders_status_history AS osh
WHERE (
o.shipping_module LIKE '%pickup_pickup%'
OR o.shipping_module LIKE '%pickup2_pickup2%'
)
AND o.orders_id = osh.orders_id
AND osh.orders_status_id = 7
AND osh.orders_status_id = 21
AND osh.orders_status_id = 31
AND osh.orders_status_id = 40
AND osh.orders_status_id != 33
AND osh.orders_status_id != 53
此查询作为第一个查询也没有过滤第三个选项
所以后来我用php
试了一下$sql = "SELECT o.orders_id, osh.orders_status_history_id
FROM
orders AS o,
orders_status_history AS osh
WHERE (
o.shipping_module LIKE '%pickup_pickup%'
OR o.shipping_module LIKE '%pickup2_pickup2%'
)
AND o.orders_id = osh.orders_id
AND osh.orders_status_id IN (7, 21, 31, 40)
AND osh.orders_status_id != 33
AND osh.orders_status_id != 53";
$sql = mysql_query($sql);
while ($row = mysql_fetch_array($sql)){
$row["orders_id"]);
if(getOrderStatus($row["orders_id"]))
echo "<br/>".$row["orders_id"];
}
function getOrderStatus($order){
$sql = "SELECT orders_status_id FROM orders_status_history WHERE orders_id = ".$order;
echo "<br/> Sql Query : ".$sql;
$sql = mysql_query($sql);
while ($status = mysql_fetch_array($sql))
if((int)$status["orders_status_id"] == 33 || (int)$status["orders_status_id"] == 53)
return false;
return true;
}
此代码花费的时间超过 30 米。我set_time_limit(0);
注意:我只能用Mysql_*因为我们的php版本是4.9
这是获取满足您条件的订单的一种方法:
SELECT o.orders_id
FROM orders o JOIN
orders_status_history osh
ON o.orders_id = osh.orders_id
WHERE (o.shipping_module LIKE '%pickup_pickup%' OR
o.shipping_module LIKE '%pickup2_pickup2%'
) AND
osh.orders_status_id IN (7, 21, 31, 40, 33, 53)
GROUP BY o.orders_id
HAVING SUM( osh.orders_status_id IN (33, 53) ) = 0;
WHERE
只选择您关心的状态。 HAVING
确保您没有最后两个。
如果您想要订单或订单行的详细信息,则需要重新加入这些表。