有没有办法在同一个查询中得到第95百分位和求和?

时间:2013-10-25 03:32:24

标签: mysql sql database performance percentile

我有一个很大的MySQL表,即使正确编制索引,每次查询也需要1秒钟(听起来不是很多,但它运行的是数千台服务器)。现在,我有四个查询通过获得第95百分位入站,第95百分位出站,以及两者的总和。

查询1:获取行数以获得第95百分位行

SELECT round(count(*)*.95 FROM traffic WHERE server_id = 1;

查询2& 3获得第95个百分点

SELECT inbound FROM traffic WHERE server_id = 1 ORDER BY inbound ASC LIMIT {95th},1
SELECT outbound FROM traffic WHERE server_id = 1 ORDER BY outbound ASC LIMIT {95th},1

查询4获取流量总和

SELECT sum(inbound+outbound) FROM traffic WHERE server_id = 1; 

你能想到我可以将这些结合起来吗?因为我需要获得第95个百分位,所以通过根据计数选择特定行来计算,我被挑战想到一种方法。例如,如果有10000行,则按升序排序并选择第9500行。

2 个答案:

答案 0 :(得分:3)

如果您愿意放弃一些精度,可以使用估计行数而不是精确行数。如果您的数据库使用InnoDB,SELECT count(*)可能会非常慢。换句话说:

  1. 要估算,您可以使用SHOW TABLE STATUS命令。它会快速闪电,但不一定100%准确。

  2. 替换您的陈述:

    SELECT inbound FROM traffic WHERE server_id = 1 ORDER BY inbound ASC LIMIT {95th},1
    

    SELECT inbound FROM traffic WHERE server_id = 1 ORDER BY inbound DESC LIMIT {5th},1
    

    结果应该相同,但速度要快20倍。只需确保在(server_id, inbound)上创建复合索引。

  3. 见2.

  4. 不管这个。

  5. 我希望获得必要数字的总时间将减少到几毫秒。

答案 1 :(得分:2)

http://planet.mysql.com/entry/?id=13588中所述:

SELECT
    SUBSTRING_INDEX(
            SUBSTRING_INDEX(
                GROUP_CONCAT( 
                    t.inbound
                    ORDER BY t.inbound
                    SEPARATOR ','
                )
            ,   ','
            ,   95/100 * COUNT(*) + 1
            )
        ,   ','  
        ,   -1  
        )                 AS `Inbound95`
    ,
    SUBSTRING_INDEX(
            SUBSTRING_INDEX(
                GROUP_CONCAT(  
                    t.outbound
                    ORDER BY t.outbound
                    SEPARATOR ','
                )
            ,   ','         
            ,   95/100 * COUNT(*) + 1 
            )
        ,   ','                       
        ,   -1                          
        )                 AS `Outbound95`
FROM   traffic AS t WHERE t.server_id = 1

会给你两个百分点

注意:您可能需要增加group_concat_max_len