【问题标题】:SQL COUNT(*) a JOIN-statement instead of COUNT(*) inside a nested SELECT-statement for better PerformanceSQL COUNT(*) 一个 JOIN 语句而不是嵌套 SELECT 语句中的 COUNT(*) 以获得更好的性能
【发布时间】:2016-04-16 04:26:28
【问题描述】:

基于http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/ 以下 SQL 查询返回给定 $radius 内最接近 $lat/$lon 对的城市数组。我添加了另一个join-statement (c.) 以显示每个城市的Country 表中的code3l-列。 总体而言,由于 3Mio 条目的数量,此语句大约需要 1.2sek

SELECT population, AccentCity, Country, code3l, name, City, Region,
       Latitude, Longitude, distance, id          
      FROM (
         SELECT z.population,z.id,
                z.AccentCity,z.Country, z.City, z.Region,
                z.Latitude, z.Longitude,
                c.name, c.code3l,
                p.radius,
                p.distance_unit
                         * DEGREES(ACOS(COS(RADIANS(p.latpoint))
                         * COS(RADIANS(z.latitude))
                         * COS(RADIANS(p.longpoint - z.longitude))
                         + SIN(RADIANS(p.latpoint))
                         * SIN(RADIANS(z.latitude)))) AS distance

          FROM worldpopulation AS z
          JOIN (   
                SELECT  '.$lat.'  AS latpoint,  '.$lon.' AS longpoint,
                        '.$radius.' AS radius,      111.045 AS distance_unit
            ) AS p ON 1=1

          JOIN (   
                SELECT * FROM countries
            ) AS c ON c.code2l = z.Country


          WHERE 
            z.population IS NOT NULL 

            AND z.latitude
             BETWEEN p.latpoint  - (p.radius / p.distance_unit)
                 AND p.latpoint  + (p.radius / p.distance_unit)
            AND z.longitude
             BETWEEN p.longpoint - (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
                 AND p.longpoint + (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
         ) AS d
     WHERE distance <= radius
     ORDER BY distance ASC';

除此之外,我还需要添加一些count(*)-statements 来返回每个城市的乘客数量。所以我试着像这样添加这些:

SELECT population, AccentCity, Country, code3l, name, City, Region,
       Latitude, Longitude, distance,id,
       (select count(*) from passengers where city_id = d.id) AS passenger,
       (select count(*) from passengers where city_id = d.id AND
                                 start = "'.$icao.'") AS passengerFromHere,
       (select count(*) from passengers where city_id = d.id AND
                             destination = "'.$icao.'") AS passengerToHere
FROM (
         SELECT z.population,z.id,
...

但名为 passengers 的表增长很快,语句的整体执行时间也随之增长

我有办法加入沉重的passengers,在更好的执行时间内获得相同的结果(城市数组及其各自的乘客)

【问题讨论】:

  • 尝试使用count(id) 而不是count(*),因为它会选择表格中的所有内容。您应该始终避免使用 *.
  • 性能随容量下降 - 这清楚地表明您需要能够支持数据增长的良好硬件。在您达到其中一台设备的限制之前,您只能做这么多。现在,您可以尝试 hack 和 slash 等等,但最终 - 即使是最好的代码或查询也达到了硬件限制。
  • 发现这篇有趣的文章:link。尝试在配置文件中使用这些值:query_cache_size = 268435456query_cache_type=1query_cache_limit=1048576
  • @AlexanderTeitelboym 注意:斜体如果您的应用程序频繁更新表,那么查询缓存将不断被清除,您将不会得到太多或任何好处”不幸的是,乘客表会经常更新。无论如何,感谢您的阅读

标签: mysql join count large-data-volumes


【解决方案1】:

我从 SQL 中取出了乘客计数语句。 构建一个 php 函数,循环遍历每个城市并将乘客计数添加到城市,如果名称为 city_id 的键存在

if(isset($cityArray[$passengers[$key[$i]]-&gt;city_id]))

代替sql语句:

(select count(*) from passengers where city_id = d.id AND
                             start = "'.$icao.'") AS passengerFromHere,

我想出的codeigniter函数是这样的:

public function add_PassengersFromHereToCitys($icao, $cityArray){

            $query = $this->db->select('count(city_id) as passengers, city_id')->from('passengers')->where('start', $icao)->group_by('city_id')->get();
            $passengers = $query->result();

            $key = array_keys($passengers);
            $size = sizeOf($key);
            for ($i=0; $i<$size; $i++){

                if(isset($cityArray[$passengers[$key[$i]]->city_id])){
                    $cityArray[$passengers[$key[$i]]->city_id]->passengerFromHere = $passengers[$key[$i]]->passengers;
                }

            }  

            return $cityArray;
        } 

已分别与第二个count(*) 完成此操作。

现在有了这个 php 循环,获得所需结果比在 sql 语句中提取日期要快得多。 但是,如果有人有修改sql语句的想法。告诉我!

【讨论】:

    猜你喜欢
    • 2012-08-13
    • 2013-05-31
    • 2016-05-21
    • 1970-01-01
    • 2018-07-09
    • 2017-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多