diff --git a/Database/MySQL/Base.hs b/Database/MySQL/Base.hs
--- a/Database/MySQL/Base.hs
+++ b/Database/MySQL/Base.hs
@@ -149,15 +149,15 @@
     else do
         StmtPrepareOK stid colCnt paramCnt _ <- getFromPacket getStmtPrepareOK p
         _ <- replicateM_ paramCnt (readPacket is)
-        _ <- unless (colCnt == 0) (void (readPacket is))  -- EOF
-        _ <- replicateM_ colCnt (readPacket is)
         _ <- unless (paramCnt == 0) (void (readPacket is))  -- EOF
+        _ <- replicateM_ colCnt (readPacket is)
+        _ <- unless (colCnt == 0) (void (readPacket is))  -- EOF
         return stid
 
 -- | Ask MySQL to prepare a query statement.
 --
 -- All details from @COM_STMT_PREPARE@ Response are returned: the 'StmtPrepareOK' packet,
--- params's 'ColumnDef', table's 'ColumnDef'.
+-- params's 'ColumnDef', result's 'ColumnDef'.
 --
 prepareStmtDetail :: MySQLConn -> Query -> IO (StmtPrepareOK, [ColumnDef], [ColumnDef])
 prepareStmtDetail conn@(MySQLConn is os _ _) (Query stmt) = do
@@ -169,9 +169,9 @@
     else do
         sOK@(StmtPrepareOK _ colCnt paramCnt _) <- getFromPacket getStmtPrepareOK p
         pdefs <- replicateM paramCnt ((decodeFromPacket <=< readPacket) is)
-        _ <- unless (colCnt == 0) (void (readPacket is))  -- EOF
-        cdefs <- replicateM colCnt ((decodeFromPacket <=< readPacket) is)
         _ <- unless (paramCnt == 0) (void (readPacket is))  -- EOF
+        cdefs <- replicateM colCnt ((decodeFromPacket <=< readPacket) is)
+        _ <- unless (colCnt == 0) (void (readPacket is))  -- EOF
         return (sOK, pdefs, cdefs)
 
 -- | Ask MySQL to closed a query statement.
diff --git a/Database/MySQL/BinLog.hs b/Database/MySQL/BinLog.hs
--- a/Database/MySQL/BinLog.hs
+++ b/Database/MySQL/BinLog.hs
@@ -124,22 +124,22 @@
             | isEOF p -> return Nothing
             | isERR p -> decodeFromPacket p >>= throwIO . ERRException
 
--- | Row based biblog event type.
+-- | Row based binlog event type.
 --
 -- It's recommended to enable row query event before 'dumpBinLog', so that you can get
 -- 'RowQueryEvent' in row based binlog(it's important for detect a table change for example),
 -- more information please refer <http://dev.mysql.com/doc/refman/5.7/en/replication-options-binary-log.html#sysvar_binlog_rows_query_log_events sysvar_binlog_rows_query_log_events>
 --
--- a 'BinLogTracker' is included so that you can roll up your own HA solutions,
+-- A 'BinLogTracker' is included so that you can roll up your own HA solutions,
 -- for example, writing the tracker to zookeeper when you done with an event.
 --
 -- The first 'Word32' field is a timestamp present when this event is logged.
 --
 data RowBinLogEvent
-    = RowQueryEvent  !Word32 !BinLogTracker !QueryEvent'
-    | RowDeleteEvent !Word32 !BinLogTracker !TableMapEvent !DeleteRowsEvent
-    | RowWriteEvent  !Word32 !BinLogTracker !TableMapEvent !WriteRowsEvent
-    | RowUpdateEvent !Word32 !BinLogTracker !TableMapEvent !UpdateRowsEvent
+    = RowQueryEvent  {-# UNPACK #-} !Word32 !BinLogTracker !QueryEvent'
+    | RowDeleteEvent {-# UNPACK #-} !Word32 !BinLogTracker !TableMapEvent !DeleteRowsEvent
+    | RowWriteEvent  {-# UNPACK #-} !Word32 !BinLogTracker !TableMapEvent !WriteRowsEvent
+    | RowUpdateEvent {-# UNPACK #-} !Word32 !BinLogTracker !TableMapEvent !UpdateRowsEvent
   deriving (Show, Eq, Generic)
 
 -- | decode row based event from 'BinLogPacket' stream.
diff --git a/Database/MySQL/BinLogProtocol/BinLogValue.hs b/Database/MySQL/BinLogProtocol/BinLogValue.hs
--- a/Database/MySQL/BinLogProtocol/BinLogValue.hs
+++ b/Database/MySQL/BinLogProtocol/BinLogValue.hs
@@ -11,7 +11,6 @@
 
 -}
 
-
 module Database.MySQL.BinLogProtocol.BinLogValue where
 
 import           Control.Applicative
@@ -47,7 +46,8 @@
 -- see 'MySQLVaule' 's note.
 --
 -- There's also no infomation about charset, so we use 'ByteString' to present both text
--- and blob types.
+-- and blob types, if you want to get text representation back, you have to query column charset
+-- infomation, and use icu or iconv to decode. IT MAY NOT BE UTF-8.
 --
 -- The @SET@ and @ENUM@ values are presented by their index's value and bitmap respectively,
 -- if you need get the string value back, you have to perform a 'DESC tablename' to get the
@@ -93,7 +93,7 @@
 getBinLogField (BINLOG_TYPE_BIT    _    bytes) = BinLogBit <$> getBits' bytes
 getBinLogField BINLOG_TYPE_TIMESTAMP           = BinLogTimeStamp <$> getWord32le
 
--- ^ a integer in @YYYYMMDD@ format, for example:
+-- A integer in @YYYYMMDD@ format, for example:
 -- 99991231 stand for @9999-12-31@
 getBinLogField BINLOG_TYPE_DATE = do
     i <- getWord24le
@@ -108,7 +108,7 @@
     ms <- fromIntegral <$> getMicroSecond fsp
     pure (BinLogTimeStamp2 s ms)
 
--- a integer in @YYYYMMDDhhmmss@, for example:
+-- A integer in @YYYYMMDDhhmmss@, for example:
 -- 99991231235959 stand for @9999-12-31 23:59:59@
 getBinLogField BINLOG_TYPE_DATETIME = do
     i <- getWord64le
@@ -149,7 +149,7 @@
     ms <- fromIntegral <$> getMicroSecond fsp
     pure (BinLogDateTime2 yyyy' mm' dd h m s ms)
 
--- ^ a integer in @hhmmss@ format(can be negative), for example:
+-- A integer in @hhmmss@ format(can be negative), for example:
 -- 8385959 stand for @838:59:59@
 getBinLogField BINLOG_TYPE_TIME = do
     i <- getWord24le
diff --git a/Database/MySQL/Connection.hs b/Database/MySQL/Connection.hs
--- a/Database/MySQL/Connection.hs
+++ b/Database/MySQL/Connection.hs
@@ -48,7 +48,7 @@
 
 -- | Everything you need to establish a MySQL connection.
 --
--- You may want some helpers in "System.IO.Streams.TLS" to setup TLS connection.
+-- To setup a TLS connection, use module "Database.MySQL.TLS" or "Database.MySQL.OpenSSL".
 --
 data ConnectInfo = ConnectInfo
     { ciHost     :: HostName
@@ -104,10 +104,10 @@
     in Auth clientCap clientMaxPacketSize clientCharset user scambleBuf db
   where
     scramble :: ByteString -> ByteString -> ByteString
-    scramble salt pass
-        | B.null pass = B.empty
+    scramble salt pass'
+        | B.null pass' = B.empty
         | otherwise   = B.pack (B.zipWith xor sha1pass withSalt)
-        where sha1pass = sha1 pass
+        where sha1pass = sha1 pass'
               withSalt = sha1 (salt `B.append` sha1 sha1pass)
 
     sha1 :: ByteString -> ByteString
@@ -125,18 +125,18 @@
     return . Just $ Packet len seqN body
   where
     loopRead acc 0 _  = return $! L.fromChunks (reverse acc)
-    loopRead acc k is = do
-        bs <- Stream.read is
+    loopRead acc k is' = do
+        bs <- Stream.read is'
         case bs of Nothing -> throwIO NetworkException
                    Just bs' -> do let l = fromIntegral (B.length bs')
                                   if l >= k
                                   then do
                                       let (a, rest) = B.splitAt (fromIntegral k) bs'
-                                      unless (B.null rest) (Stream.unRead rest is)
+                                      unless (B.null rest) (Stream.unRead rest is')
                                       return $! L.fromChunks (reverse (a:acc))
                                   else do
                                       let k' = k - l
-                                      k' `seq` loopRead (bs':acc) k' is
+                                      k' `seq` loopRead (bs':acc) k' is'
 
 -- | Close a MySQL connection.
 --
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
 Is it fast?
 ----------
 
-In short, `select`(decode) is about 2 times slower than pure c/c++, `insert` (encode) is about 1.5 times slower than pure c/c++, there're many factors involved(tls, prepared statment, batch using multiple statement):
+In short, `select`(decode) is about 2 times slower than pure c/c++ but 5 times faster than `mysql-simple`, `insert` (encode) is about 1.5 times slower than pure c/c++, there're many factors involved(tls, prepared statment, batch using multiple statement):
 
 <img src="https://github.com/winterland1989/mysql-haskell/blob/master/benchmark/result.png?raw=true" width="100%">
 
@@ -34,6 +34,65 @@
 + no replication protocol support.
 
 `mysql-haskell` is intended to solve these problems, and provide foundation for higher level libraries such as groundhog and persistent, so that accessing MySQL is both fast and easy in haskell.
+
+Guide
+-----
+
+The `Database.MySQL.Base` module provides everything you need to start making queries:
+
+```haskell
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main where
+
+import Database.MySQL.Base
+import qualified System.IO.Streams as Streams
+
+main :: IO () 
+main = do
+    conn <- connect
+        defaultConnectInfo {ciUser = "username", ciPassword = "password", ciDatabase = "dbname"}
+    (defs, is) <- query_ conn "SELECT * FROM some_table"
+    print =<< Streams.toList is
+```
+
+`query/query_` will return a column definition list, and an `InputStream` of rows, you should consume this stream completely before start new queries.
+
+It's recommanded to use prepared statement to improve query speed:
+
+```haskell
+    ...
+    s <- prepareStmt conn "SELECT * FROM some_table where person_age > ?"
+    ...
+    (defs, is) <- queryStmt s [MySQLInt32U 18]
+    ...
+```
+
+If you want to do batch inserting/deleting/updating, you can use `executeMany` to save considerable time.
+
+The `Database.MySQL.BinLog` module provides binlog listenning functions and row-based event decoder, following program will automatically get last binlog position, and print every row event it receives:
+
+```haskell
+{-# LANGUAGE LambdaCase #-}
+module Main where
+
+import           Control.Monad         (forever)
+import qualified Database.MySQL.BinLog as MySQL
+import qualified System.IO.Streams     as Streams
+
+main :: IO () 
+main = do
+    conn <- MySQL.connect 
+        MySQL.defaultConnectInfo {ciUser = "username", ciPassword = "password", ciDatabase = "dbname"}
+    MySQL.getLastBinLogTracker conn >>= \ case
+        Just tracker -> do
+            es <- MySQL.decodeRowBinLogEvent =<< MySQL.dumpBinLog conn 1024 tracker False
+            forever $ do
+                Streams.read es >>= \ case
+                    Just v  -> print v
+                    Nothing -> return ()
+        Nothing -> error "can't get latest binlog position"
+```
 
 Build Test Benchmark
 --------------------
diff --git a/mysql-haskell.cabal b/mysql-haskell.cabal
--- a/mysql-haskell.cabal
+++ b/mysql-haskell.cabal
@@ -1,5 +1,5 @@
 name:                mysql-haskell
-version:             0.4.0.0
+version:             0.4.1.0
 synopsis:            pure haskell MySQL driver
 description:         pure haskell MySQL driver
 license:             BSD3
