4

我有这个查询,它返回给定区域中的所有 POI:

    $query = $em
            ->createQuery(
                    'SELECT f FROM MyApplication\MyBundle\Entity\POI p
            WHERE (p.latitude BETWEEN :southEastLatitude AND :norhtWestLatitude) AND
                  (p.longitude BETWEEN :southEastLongitude AND :norhtWestLongitude)
            ORDER BY p.name
    ');

    $query->setParameter(":norhtWestLatitude", $northWestLat);
    $query->setParameter(":norhtWestLongitude", $northWestLng);
    $query->setParameter(":southEastLatitude", $southEastLat);
    $query->setParameter(":southEastLongitude", $southEastLng);

如果我尝试访问一个小区域(参数差异很小),我成功地得到了结果。我想我得到的结果多达 1000 行......我不太确定。

如果我尝试访问更大的区域,我会得到一个空的结果集......

不知何故,使用更大区域的参数触发相同的查询,我得到了正确的结果集(~1060 行)。

所以我想知道学说的局限性(甚至是 Symfony ???我在 Symfony2 项目中使用学说),有吗?我也试过了,$query->setMaxResults(999999999);但没有帮助...

有人有同样的问题吗?

编辑:也许 php 内存使用率很高?我在 getresult 之前和之后添加了这些行:

echo "Memory usage before: " . (memory_get_usage() / 1024) . " KB" . PHP_EOL;
echo "Memory usage after: " . (memory_get_usage() / 1024) . " KB" . PHP_EOL;

输出是:

之后的内存使用量:5964.0625 KB

之后的内存使用量:10019.421875 KB

编辑: 奇怪的测试:

1)如果我使用这些参数进行测试:

WHERE
    (f.latitude BETWEEN 45.64273082966722 AND 47.29965978937995) AND
    (f.longitude BETWEEN 4.93262593696295 AND  9.99999999999999)

我得到 923 行(正常行为)

2) 如果我将参数 9.999999999999 更改为 10.000000000(或大于 9.9999999 的某个数字),我的应用程序中将得到一个空的结果集。数据库仍然返回 923 行(对于 10.000000000)。

编辑: 我可以解决这个问题,在这里讨论:https ://groups.google.com/d/msg/doctrine-user/qLSon6m4nM4/y5vLztHcbDgJ

4

2 回答 2

2

从 Doctrine2 邮件列表中,我了解到您将属性映射为“字符串”类型:

/** @ORM\Column(name="latitude", type="string", length=255, nullable=false) */
private $latitude;

/** @ORM\Column(name="longitude", type="string", length=255, nullable=false) */
private $longitude;

这意味着您的数据库将具有这些属性的 VARCHAR 列。因此,当数据库运行您的查询时,它将执行字符串比较。

字符串比较不同于(普通)数字比较。查看这些结果:

$a = 1234567890;
$b = 987654321;

echo $a == $b ? '0' : ($a < $b ? '-1' : '1');   // output:  1 (means $a is bigger than $b)

echo strcmp( $a, $b );                          // output: -8 (means $a is smaller than $b)

所以最好将属性映射为代表数据库中数字的东西(DECIMAL 是一个不错的选择):

/** @ORM\Column(name="latitude", type="decimal", nullable=false) */
private $latitude;

/** @ORM\Column(name="longitude", type="decimal", nullable=false) */
private $longitude;

PS:您提到自己执行查询时会得到有效结果。这可能是因为你做了:

... latitude BETWEEN 45.64273082966722 AND 47.29965978937995 ...

但是 Doctrine(因为您将属性映射为字符串)会:

... latitude BETWEEN '45.64273082966722' AND '47.29965978937995' ...

注意这里的引号。这两个语句的处理方式有很大不同,就像我的测试用例显示的那样;)

于 2013-05-29T20:03:24.393 回答
1

这可能与内存使用有关。请检查您的 apache 日志中是否存在内存错误。

如本文所指出的那样,选择大量数据时可能会有所帮助$query->iterate()而不是使用。$query->getResult()

要检查您的查询是否生成正确的 SQL,您可以记录或以其他方式输出调用结果$query->getSQL()(在设置参数之后)。将生成的 SQL 提供给您选择的数据库客户端,以查看是否返回所需的结果。

于 2013-05-28T07:07:25.013 回答