繁体   English   中英

使用MySQL大型数据库进行慢查询

[英]Slow queries with MySQL large database

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

例子

ipStart: 3579374832
ipEnd: 3579374839

现在,我想从另一个表中选择visit_count 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万行。

我怎样才能使速度更快?

使用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将获得一行,但未定义哪一行(即可以是该cookie ID附带的任何user_id,ip地址和最后访问日期)。

您可以简化第一选择。 您不需要选择ipaddress之外的任何字段。 您也不需要订购或分组结果。 如果你想要独一无二的ipaddress ES,只是用distinct

select distinct ipaddress
from visit_count
where last_visit between '$firstDayOfMonth' and '$lastDayOfMonth' 
    and user_id = '$userId'

即使第二张表有5万行,选择的内容似乎也不多。 在我的机器上,即使没有索引,也只需要一秒钟的时间。

如果你想反正简化它,你可以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'

1)使用更好的查询,像其他建议给您的

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

3)不知道您使用的是mysql还是mysqli ...无论如何都使用比fetch_array更快的fetch_assoc

有了这三个技巧,你应该没事

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM