写一个更好的循环

时间:2017-01-17 06:56:25

标签: php mysql pdo

我正在创建一个脚本,用于搜索数据库并查找处于Realtors纬度和经度边界范围内的客户。如果客户纬度和长坐标在房地产经纪人的纬度和长边界范围内,则此脚本将仅通过电子邮件发送该客户范围内的房地产经纪人。我正在使用CRON作业来运行php脚本。我得到了脚本,通过电子邮件发送给房地产经纪人范围内的每个人,但当第三个房地产经纪人进入数据库时,即使纬度和长度超出范围,电子邮件也会转到第三个房地产经纪人。

如果客户端位于该房地产经纪人的范围内,并且仅向Realtor 发送电子邮件,则如何编写更好循环,其中每行都会被检查?感谢。

这是我的SQL代码。

CREATE TABLE `realtors` (
    `rid` int(11) NOT NULL AUTO_INCREMENT,
    `rEmail` varchar(255) NOT NULL,
    `rZipCode` int(10) NOT NULL,
    `rDist` int(11) NOT NULL,
    `rlatitude` numeric(30,15) NOT NULL,
    `rlongitude` numeric(30,15) NOT NULL,
  PRIMARY KEY (`rid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

CREATE TABLE `customers` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `eMail` varchar(255) NOT NULL,
    `zipCode` int(11) NOT NULL,
    `clatitude` numeric(30,15) NOT NULL,
    `clongitude` numeric(30,15) NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

这是我的PHP代码。

<?php
use geocodeloc\GeoLocation as GeoLocation;
require_once 'geocodeloc/GeoLocation.php';
//require_once 'phpmailer/PHPMailerAutoload.php';

$db = getDB();
//database prep for customers
$cust = $db->prepare("SELECT fullName, eMail, clatitude, clongitude FROM customers ORDER BY id DESC");
$cust->bindParam("fullName", $fullName,PDO::PARAM_STR);
$cust->bindParam("zipCode", $zipCode,PDO::PARAM_STR);
$cust->bindParam("eMail", $email,PDO::PARAM_STR);
$cust->bindParam("clatitude", $clatitude,PDO::PARAM_STR);
$cust->bindParam("clongitude", $clongitude,PDO::PARAM_STR);
$cust->execute();
$cust->rowCount();

//database prep for realtors
$realt = $db->prepare("SELECT rEmail, rDist, rlatitude, rlongitude FROM realtors ORDER BY rid DESC");
$realt->bindParam("rZipCode", $rZipCode,PDO::PARAM_STR);
$realt->bindParam("rEmail", $rEmail,PDO::PARAM_STR);
$realt->bindParam("rDist", $rDist,PDO::PARAM_STR);
$realt->bindParam("rlatitude", $rlatitude,PDO::PARAM_STR);
$realt->bindParam("rlongitude", $rlongitude,PDO::PARAM_STR);
$realt->execute();
$realt->rowCount();

$i = -1;

while ($realtor_row = $realt ->fetch(PDO::FETCH_ASSOC) AND $customers_row = $cust ->fetch(PDO::FETCH_ASSOC)) {
   $i++;
        $realtLatLong = GeoLocation::fromDegrees( $realtor_row['rlatitude'], $realtor_row['rlongitude']);
        $coordinates = $realtLatLong->boundingCoordinates($realtor_row['rDist'], 'miles');

              //look to see if customers latitude and longitude is within range of the realtors lat and long boundaries.
          if($customers_row['clatitude'] && $customers_row['clongitude'] <= $coordinates){
           //email the realtor

          // the message
          $msgBody = "This is a test";

          // use wordwrap() if lines are longer than 70 characters
          $msgBody = wordwrap($msgBody,70);

          $Mailto = $realtor_row['rEmail'];
          $FromName = $customers_row['fullName'];

          // send email
          mail($Mailto, $FromName , $msgBody);

        }else{
         //send to debug log
        }

};
?>

2 个答案:

答案 0 :(得分:2)

循环遍历整个结果集并进行计算将很快杀死您的数据库。循环通过一个表,然后循环通过另一个表进行距离比较将更快地杀死您的数据库。幸运的是,这是车轮的重新发明。 Mysql通过ST_Distance

为此内置了功能
SELECT * FROM realtors INNER JOIN customers WHERE ST_within(customers.loc, realtors.loc) < 10; /* location in degrees */

其中一度大约111公里。您需要按照以下方式更改表格

CREATE TABLE `realtors` (
    `rid` int(11) NOT NULL AUTO_INCREMENT,
    `rEmail` varchar(255) NOT NULL,
    `rZipCode` int(10) NOT NULL,
    `rDist` int(11) NOT NULL,
    `loc` point NOT NULL,

  PRIMARY KEY (`rid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

CREATE TABLE `customers` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `eMail` varchar(255) NOT NULL,
    `zipCode` int(11) NOT NULL,
    `loc` POINT not null,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

当然这需要mysql 5.7

使用空间数据类型意味着您可以使用索引进行空间查找。在RDBS中,如果表包含N行,则具有indes意味着您无需检查所有这N行以查找结果。因此,在这里使用空间数据+索引,您可以避免在单独的列中使用lat,lng时可能具有的NxM时间复杂度。

答案 1 :(得分:0)

无论您编写代码的速度有多快,复杂性仍然是NxM。

您应该做的第一件事是在Customer和Realtor之间创建一个关系,即一个包含Customer.id和Realtor.id的表。第一次填充此表时进行点击(无需更改代码)。之后,您只需在每次添加客户或房地产经纪人时创建关系。

当您发送电子邮件时,您只需要查看关系表。