Skip to content

Instantly share code, notes, and snippets.

@jorpic
Last active August 29, 2015 14:24
Show Gist options
  • Save jorpic/743858bdd326e68faf1b to your computer and use it in GitHub Desktop.
Save jorpic/743858bdd326e68faf1b to your computer and use it in GitHub Desktop.
pg update benchmark

Тест проводился для 2.5 млн записей.

При записи изменений в один поток:

  • 90% запросов укладывается в 140мс;
  • 95% запросов укладывается в 240мс;
  • максимальное время выполнения запроса 489мс.

При записи изменений в два потока:

  • 90% запросов укладывается в 300мс;
  • 95% запросов укладывается в 375мс;
  • максимальное время выполнения запроса 1803мс.

img

После почти двух суток работы теста (44 часа) время на выборку сильно не изменилось (90% запросов выполняется за 10 секунд).

img

Если сделать VACUUM VERBOSE, видно что мусорных версий накопилось не очень много. Возможно нужен более длительный тест, чтобы увидеть влияние старых версий на выборку.

> INFO:  vacuuming "public.xxx"
> INFO:  scanned index "xxx_pkey" to remove 126887 row versions
> DETAIL:  CPU 0.09s/0.42u sec elapsed 23.43 sec.
> INFO:  "xxx": removed 126887 row versions in 93750 pages
> DETAIL:  CPU 0.79s/2.70u sec elapsed 131.56 sec.
> INFO:  index "xxx_pkey" now contains 2500007 row versions in 6897 pages
> DETAIL:  71703 index row versions were removed.
> 0 index pages have been deleted, 0 are currently reusable.
> CPU 0.00s/0.00u sec elapsed 0.02 sec.
> INFO:  "xxx": found 98235 removable, 2503728 nonremovable row versions in 242438 out of 242438 pages
> DETAIL:  3721 dead row versions cannot be removed yet.
> There were 478789 unused item pointers.
> 0 pages are entirely empty.
> CPU 2.84s/6.36u sec elapsed 403.06 sec.

Нужно настроить carbon-aggregator чтобы для секундной метки брался максимум (иначе данные бессмысленные получаются).

{-# LANGUAGE QuasiQuotes #-}
import Control.Applicative
import Control.Monad
import Control.Concurrent
import System.Environment (getArgs)
import System.Clock
import System.Random.MWC
import qualified Data.ByteString as B
import qualified Data.ByteString.Builder as B
import qualified Data.ByteString.Lazy as L
import Database.PostgreSQL.Simple
import Database.PostgreSQL.Simple.Copy
import Database.PostgreSQL.Simple.SqlQQ
import Network.Metric.Sink.Graphite as M
main = getArgs >>= \case
["fill", n] -> do
time <- timeit $ fillDB (read n)
let msec = time `div` 1000000
putStrLn $ "Database populated in " ++ show msec ++ " milliseconds."
["select", n] -> do
putStrLn $ "Select all rows in loop with " ++ n ++ " milliseconds delay."
select (read n)
["update", n] -> do
putStrLn $ "Update random rows from " ++ n ++ " thread(s)."
update (read n :: Int)
_ -> do
putStrLn "Usage:"
putStrLn "\tfill <n> - crate new table with <n> rows."
putStrLn "\tselect <n> - select * in a loop with <n> milliseconds delay."
putStrLn "\tupdate <n> - run <n> threads updating random rows."
connectPG = connectPostgreSQL "dbname=user"
connectGR = M.open Nothing "127.0.0.1" 2003
timeit f = do
start <- getTime Monotonic
res <- f
end <- getTime Monotonic
let diff = timeSpecAsNanoSecs $ diffTimeSpec end start
return $! res `seq` diff
dummyRow i = L.toStrict $ L.concat
$ [ B.toLazyByteString $ B.intDec i
, "\t"
]
++ [B.toLazyByteString (B.intDec x) | x <- [i..i+100]]
++ ["\n"]
fillDB numRows = do
pg <- connectPG
withTransaction pg $ do
execute_ pg [sql| DROP TABLE IF EXISTS xxx |]
execute_ pg [sql|
CREATE TABLE xxx (key int primary key, value text not null)
|]
copy_ pg [sql| COPY xxx FROM STDIN |]
forM_ [0..numRows] $ putCopyData pg . dummyRow
putCopyEnd pg
select msec = do
pg <- connectPG
gr <- connectGR
forever $ do
let q = query_ pg [sql| SELECT key, value FROM xxx |] :: IO [(Int, B.ByteString)]
time <- timeit (length <$> q)
push gr $ Timer "pg" "select" (fromIntegral time / 1000)
threadDelay (msec * 1000)
update numThreads = do
pg <- connectPG
gr <- connectGR
rnd <- createSystemRandom
[[count]] <- query_ pg [sql| SELECT count(*) from xxx |] :: IO [[Int]]
forever $ do
key <- uniformR (0,count-1) rnd :: IO Int
i <- uniformR (0,1000000) rnd :: IO Int
let val = L.concat [B.toLazyByteString (B.intDec x) | x <- [i..i+100]]
time <- timeit $ execute pg [sql| UPDATE xxx set value = ? WHERE key = ? |] (val, key)
push gr $ Timer "pg" "update" (fromIntegral time / 1000)
name: pg-bench
version: 0.1.0.0
build-type: Simple
cabal-version: >=1.10
executable pg-bench
default-language: Haskell2010
hs-source-dirs: .
main-is: Main.hs
build-depends:
base >=4.7 && <4.8,
clock,
bytestring,
postgresql-simple,
network-metrics,
mwc-random
default-extensions:
OverloadedStrings,
LambdaCase
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment