MySQL大型数据库查询速度慢

时间:2014-06-13 08:18:39

标签: php mysql sql

我有一个包含IP范围的表​​ipaddresses。列是:ipStart,ipEnd

的例子
ipStart: 3579374832
ipEnd: 3579374839

现在我想从另一个表中选择300个IP地址:visit_count。基于这300个地址,我想检查IP地址是否在表ipaddresses

中的任何IP范围内

我目前的代码:

$results = $database->query("SELECT user_id, 
                            DATE_FORMAT(last_visit, '%Y-%m-%d') as datumet, 
                            cookieId, ipaddress 
                          FROM `visit_count` 
                          WHERE last_visit BETWEEN 
                                      '$firstDayOfMonth' AND '$lastDayOfMonth' 
                          AND user_id = '$userId' 
                          GROUP BY cookieId 
                          ORDER BY last_visit ASC");        

$rows = $database->loadObjectList($results);    


foreach ( $rows as $row ) {

    $ipaddressLong = ip2long($row->ipaddress);

    // This is where its very very slow
    $selO = $database->query("SELECT ipStart, ipEnd FROM `ipaddresses` 
                        WHERE '$ipaddressLong' BETWEEN `ipStart` AND `ipEnd`");
    $rowO = $database->getrow($selO);

}

结果是一个非常慢的查询,消耗了大量的cpu。

ipaddresses包含ipStartipEnd的索引,包含大约5万行。

如何让它更快?

3 个答案:

答案 0 :(得分:0)

使用JOIN对单个查询进行快速而脏的更改: -

SELECT a.ipStart, a.ipEnd 
FROM `ipaddresses` a
INNER JOIN
(
    SELECT user_id, DATE_FORMAT(last_visit, '%Y-%m-%d') as datumet, cookieId, inet_aton(ipaddress ) AS ipaddressLong
    FROM `visit_count` 
    WHERE last_visit BETWEEN '$firstDayOfMonth' AND '$lastDayOfMonth' 
    AND user_id = '$userId' 
    GROUP BY cookieId 
) b 
ON b.ipaddressLong BETWEEN a.ipStart AND a.ipEnd 

请注意,这可能会简化。但是,这取决于您使用 GROUP BY cookieId 。目前这将获得每个cookie id一行,但是哪一行是未定义的(即,可以是任何user_id,ip地址以及与该cookie id一起的最后访问日期)。

答案 1 :(得分:0)

您可以简化第一个选择。您不需要选择ipaddress以外的任何字段。您也不需要订购或分组结果。如果您想要唯一的ipaddress es,请使用distinct

select distinct ipaddress
from visit_count
where last_visit between '$firstDayOfMonth' and '$lastDayOfMonth' 
    and user_id = '$userId'
即使第二个表有50k行,300 p选择似乎也不多。在我的机器上,即使没有索引,也只需要几分之一秒。

如果您想要简化它,可以使用

join两个表格
select ipstart, ipend
from ipaddresses i
join visit_count v on inet_aton(v.ipaddress) between i.ipstart and i.ipend
where v.last_visit between '$firstDayOfMonth' and '$lastDayOfMonth'
    and v.userid = '$userId'

答案 2 :(得分:0)

1)使用比其他建议更好的查询

2)您是否为所需的字段定义了索引?

3)不知道你是否使用mysql或mysqli ...无论如何使用fetch_assoc比fetch_array更快

这3个技巧你应该没问题