2013-10-25 67 views
3

我有一個很大的MySQL表,即使正確索引它可能需要1秒的每個查詢(聽起來不是很多,但它運行數千個服務器)。目前,我有四個查詢需要獲得第95百分位入境,第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

正如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

+0

從技術上講,這在單個查詢中給出了答案。但是,它會變得很慢 – mvp

+0

@mvp由於查詢排序順序不同(蘋果和橙子),因此無法以有效的方式將兩個第95百分位組合成一個查詢。 – SheetJS

+0

那麼,即使你用第5個百分點代替第95百分位數(請參閱我的回答),它會使你的查詢速度更快。 – mvp

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. 離開這個孤獨。

我期望獲得必要數字的總時間將縮短到幾毫秒。

+0

這是如何結合任何查詢? – SheetJS

+0

@Nirk:不是。 OP對性能抱怨,並認爲將其合併成一個查詢會加快速度。我提出的解決方案使其非常快速,這實際上是OP所困擾的。 – mvp

+0

對每個入站,出站而不僅僅是server_id使用複合查詢,似乎令人難以置信地增加了索引大小,僅削減了大約2%的時間。有沒有什麼我應該做的不僅僅是:ADD INDEX'compound' USING BTREE('server_id' ASC,'inbound' ASC); – Devon

相關問題