Skip to content

Commit 348195b

Browse files
committed
Optimize execute
Avoiding the statment close by using the unnamed statment improves the lower bound perf by ~1/3: test bench_execute ... bench: 425429 ns/iter (+/- 24970) test bench_naiive_execute ... bench: 607967 ns/iter (+/- 53434) cc rust-postgres#83
1 parent 80b7fa8 commit 348195b

3 files changed

Lines changed: 51 additions & 13 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ keywords = ["database", "sql"]
1313
name = "postgres"
1414
path = "src/lib.rs"
1515
test = false
16+
bench = false
1617

1718
[[test]]
1819
name = "test"

benches/bench.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
extern crate test;
2+
extern crate postgres;
3+
4+
use test::Bencher;
5+
6+
use postgres::{Connection, SslMode};
7+
8+
#[bench]
9+
fn bench_naiive_execute(b: &mut test::Bencher) {
10+
let conn = Connection::connect("postgres://postgres@localhost", &SslMode::None).unwrap();
11+
conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]).unwrap();
12+
13+
b.iter(|| {
14+
let stmt = conn.prepare("UPDATE foo SET id = 1").unwrap();
15+
let out = stmt.execute(&[]).unwrap();
16+
stmt.finish().unwrap();
17+
out
18+
});
19+
}
20+
21+
#[bench]
22+
fn bench_execute(b: &mut test::Bencher) {
23+
let conn = Connection::connect("postgres://postgres@localhost", &SslMode::None).unwrap();
24+
conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]).unwrap();
25+
26+
b.iter(|| {
27+
conn.execute("UPDATE foo SET id = 1", &[]).unwrap()
28+
});
29+
}

src/lib.rs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ use std::cell::{Cell, RefCell};
7474
use std::collections::{RingBuf, HashMap};
7575
use std::io::{BufferedStream, IoResult};
7676
use std::io::net::ip::Port;
77+
use std::iter::IteratorCloneExt;
7778
use std::mem;
7879
use std::fmt;
7980
use std::result;
@@ -512,9 +513,13 @@ impl InnerConnection {
512513

513514
try!(self.wait_for_ready());
514515

515-
// now that the connection is ready again, get unknown type names
516-
try!(self.set_type_names(param_types.iter_mut()));
517-
try!(self.set_type_names(result_desc.iter_mut().map(|d| &mut d.ty)));
516+
// now that the connection is ready again, get unknown type names,
517+
// but not if stmt_name is "" since that'll blow away the statement
518+
// and we don't care about result values anyway
519+
if stmt_name != "" {
520+
try!(self.set_type_names(param_types.iter_mut()));
521+
try!(self.set_type_names(result_desc.iter_mut().map(|d| &mut d.ty)));
522+
}
518523

519524
Ok((param_types, result_desc))
520525
}
@@ -542,15 +547,15 @@ impl InnerConnection {
542547
-> Result<CopyInStatement<'a>> {
543548
let mut query = vec![];
544549
let _ = write!(&mut query, "SELECT ");
545-
let _ = util::comma_join(&mut query, rows.iter().map(|&e| e));
550+
let _ = util::comma_join(&mut query, rows.iter().cloned());
546551
let _ = write!(&mut query, " FROM {}", table);
547552
let query = String::from_utf8(query).unwrap();
548553
let (_, result_desc) = try!(self.raw_prepare("", query[]));
549554
let column_types = result_desc.into_iter().map(|desc| desc.ty).collect();
550555

551556
let mut query = vec![];
552557
let _ = write!(&mut query, "COPY {} (", table);
553-
let _ = util::comma_join(&mut query, rows.iter().map(|&e| e));
558+
let _ = util::comma_join(&mut query, rows.iter().cloned());
554559
let _ = write!(&mut query, ") FROM STDIN WITH (FORMAT binary)");
555560
let query = String::from_utf8(query).unwrap();
556561
let stmt_name = self.make_stmt_name();
@@ -839,10 +844,16 @@ impl Connection {
839844
///
840845
/// On success, returns the number of rows modified or 0 if not applicable.
841846
pub fn execute(&self, query: &str, params: &[&ToSql]) -> Result<uint> {
842-
let stmt = try!(self.prepare(query));
843-
let out = try!(stmt.execute(params));
844-
try!(stmt.finish());
845-
Ok(out)
847+
let (param_types, result_desc) = try!(self.conn.borrow_mut().raw_prepare("", query));
848+
let stmt = Statement {
849+
conn: self,
850+
name: "".into_string(),
851+
param_types: param_types,
852+
result_desc: result_desc,
853+
next_portal_id: Cell::new(0),
854+
finished: true, // << !!
855+
};
856+
stmt.execute(params)
846857
}
847858

848859
/// Execute a sequence of SQL statements.
@@ -988,10 +999,7 @@ impl<'conn> Transaction<'conn> {
988999

9891000
/// Like `Connection::execute`.
9901001
pub fn execute(&self, query: &str, params: &[&ToSql]) -> Result<uint> {
991-
let stmt = try!(self.prepare(query));
992-
let out = try!(stmt.execute(params));
993-
try!(stmt.finish());
994-
Ok(out)
1002+
self.conn.execute(query, params)
9951003
}
9961004

9971005
/// Like `Connection::batch_execute`.

0 commit comments

Comments
 (0)