4

我有一个大的 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 行。

4

2 回答 2

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. 别管这个。

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

于 2013-10-25T03:47:33.013 回答
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

于 2013-10-25T03:46:22.640 回答