Php MySQL大型数据库的慢速查询

Php MySQL大型数据库的慢速查询,php,mysql,sql,Php,Mysql,Sql,我有一个包含IP范围的IP地址表。列为:ipStart、ipEnd 举例 ipStart: 3579374832 ipEnd: 3579374839 现在我想从另一个表中选择300个IP地址:visit\u count。根据这300个地址,我想检查ip地址是否在表ipaddresses中的任何ip的范围内 我当前的代码: $results = $database->query("SELECT user_id, DATE_FORMA

我有一个包含IP范围的IP地址表。列为:ipStart、ipEnd

举例

ipStart: 3579374832
ipEnd: 3579374839
现在我想从另一个表中选择300个IP地址:visit\u 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

IPAddress具有ipStart和ipEnd的索引,包含大约5万行


我如何才能更快地执行此操作?

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

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 

请注意,这可能会被简化。不过,这取决于您对cookieId的使用。目前,这将为每个cookie id获取一行,但哪一行是未定义的,即,可以是任何用户id、ip地址和与该cookie id一起的最后访问日期。

您可以简化第一次选择。您不需要选择ipaddress之外的任何字段。您也不需要对结果进行排序或分组。如果您想要唯一的IP地址,只需使用distinct即可

300个选择似乎并不多,即使第二个表有50k行。在我的机器上,即使没有索引,也只需要几分之一秒

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

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'

1使用更好的查询,就像建议您使用的其他查询一样

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

3不知道您是使用mysql还是mysqli…无论如何,使用fetch\u assoc比fetch\u数组更快


有了这3个技巧,你应该没问题了

你有什么理由不能加入吗?ipaddress表是否在ipStart和ipEnd MySQL上都有覆盖索引通常只在一个表上使用一个索引,因此如果两列有助于查询,那么索引应该覆盖这两个索引—不熟悉联接,不知道如何实现它你能在ipStart和ipEnd上创建一个索引吗?@webnomad-yepp我现在就这么做了使用连接的原因是它意味着你要执行一个查询,而不是300个查询。最奇怪的是,在这两个表中存储了两种不同格式的ip地址。查询需要11秒您可以发布表声明,包括索引和您所做的解释吗?
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'