2010-07-01 368 views
7

我有一個十億行的表,我想確定的平均時間與時間的標準偏差爲形式的幾個疑問:統計數據的查詢時間(PostgreSQL的)

select * from mytable where col1 = '36e2ae77-43fa-4efa-aece-cd7b8b669043'; 
select * from mytable where col1 = '4b58c002-bea4-42c9-8f31-06a499cabc51'; 
select * from mytable where col1 = 'b97242ae-9f6c-4f36-ad12-baee9afae194'; 

.... 

我有一千個存儲在另一個表中的col1的隨機值。

是否有某種方式來存儲多久,這些查詢在一個單獨的表了(毫秒),這樣我就可以在它上面運行的一些統計數據?例如:對於我的隨機表中的每個col1,執行查詢,記錄時間,然後將其存儲在另一個表中。

完全不同的方法就可以了,只要我能留內的PostgreSQL(即我不想寫一個外部程序來做到這一點)。

回答

6

你知道EXPLAIN statement的?

該命令顯示PostgreSQL規劃器爲所提供的語句生成的執行計劃。執行規劃顯示如何通過語句引用的表(一個或多個)將被掃描 - 通過簡單的順序掃描,索引掃描等 - 如果引用了多個表,什麼樣的連接算法將被用來彙集來自各所要求的行輸入表。

顯示屏的最關鍵的部分是預計的語句執行成本,這是規劃者它需要多長時間來運行該語句的猜測(磁盤頁面抓取的單位來衡量)。實際上顯示了兩個數字:可以返回第一行之前的啓動時間以及返回所有行的總時間。對於大多數查詢的總時間是最重要的,但在環境下,比如一個EXISTS子查詢,規劃器將選擇最小啓動時間而不是最小總時間(因爲執行器在獲取一條記錄後總是要停下來)。另外,如果你限制的行數與LIMIT子句返回,規劃使得終端成本之間取得適當的插值計算哪個規劃開銷最省。

ANALYZE選項將導致實際執行的語句,而不僅僅是規劃。每個計劃節點中花費的總時間(以毫秒爲單位)和實際返回的總行數將被添加到顯示中。這對於瞭解規劃人員的估計是否接近實際很有用。

能很容易地編寫一個腳本,您的查詢每個表中的隨機值確實的EXPLAIN ANALYZE,輸出保存到一個文件/表格/等

+0

有什麼方法可以輸出時間,這樣我就不必解析文件了嗎?這是我必須做的事,但似乎應該有一個更直接的方法。 – 2010-07-01 18:23:43

+0

'psql -c「EXPLAIN ANALYZE select * from mytable where col1 ...」| grep「總運行時間」' – 2010-07-01 18:26:03

+0

如果可能的話,我真的很想在SQL中完全做到這一點。似乎我應該能夠將它在psql交互式shell中直接返回的運行時作爲值存儲。 你的回答是非常正確的,而且如果沒有人能給我一個純粹的SQL答案,我一直在計劃做什麼。 感謝您的時間! – 2010-07-01 18:35:54

11

您需要更改PostgreSQL配置文件。

不啓用該屬性:

log_min_duration_statement = -1  # -1 is disabled, 0 logs all statements          
             # and their durations, > 0 logs only          
             # statements running at least this number         
             # of milliseconds    

在此之後,執行時間將被記錄,您將能夠弄清楚到底有多糟糕(或好)正在執行查詢。

您也可以使用一些日誌分析工具來進行進一步的分析提供真棒HTML輸出如pgfouine

0

你不能做到這一點的SQL,因爲即使你將能夠每本聲明呼籲在一個循環中,每次調用NOW()將返回相同的結果,因爲你是在一個單一的交易。

只需創建一個自己的易失性now()函數,就可以在每次調用時返回另一個值。

2

直接,不,沒有。但是,您可以通過在對時間感興趣的查詢之前和之後檢查時間來做出間接且相當接近的估算。

$sql = "Your Query"; 
$bm = "SELECT extract(epoch FROM clock_timestamp())"; 
$query = "{$bm}; {$sql}; {$bm};"; 

功能clock_timestamp()爲您提供語句啓動時的服務器實際時間。由於該SELECT沒有涉及任何表格,我們可以預計它幾乎是瞬間的。我想任何Pg驅動程序都支持多個查詢;重要的是這3個查詢(真正的一個和兩個額外的)一起去,否則你會測量數據傳輸時間以及...

對於PHP我有一個函數來處理這個問題。總結如下:

<?php 

function pgquery($sql, $conn) 
{ 
    // Prepend and append benchmarking queries 
    $bm = "SELECT extract(epoch FROM clock_timestamp())"; 
    $query = "{$bm}; {$sql}; {$bm};"; 

    // Execute the query, and time it (data transport included) 
    $ini = microtime(true); 

    pg_send_query($conn, $query); 

    while ($resource = pg_get_result($conn)) 
    { 
     $resources[] = $resource; 
    } 

    $end = microtime(true); 

    // "Extract" the benchmarking results 
    $q_ini = pg_fetch_row(array_shift($resources)); 
    $q_end = pg_fetch_row(array_pop($resources)); 

    // Compute times 
    $time = round($end - $ini, 4);    # Total time (inc. transport) 
    $q_time = round($q_end[0] - $q_ini[0], 4); # Query time (Pg server only) 

    return $resources; 
} 

?> 

我剛剛在那裏留下了基礎知識。 $ conn保存一個到Pg連接的鏈接,$ resources是一個返回的pg資源數組(如果你在$ sql中發送了多個查詢)。

$ time保留查詢離開Pg服務器以來的總時間,直到結果到達。 $ q-time只包含你想要的實際查詢時間(或者非常好的近似值)。

添加錯誤處理和其他處理你喜歡,我有很多,但它與你的問題無關。