Shay Rojansky
Long-time Linux/open source developer/enthusiast (installed Slackware somewhere in 1994/5)
Owner of Npgsql
PostgreSQL driver
Entity Framework (O/RM) providers
Microsoft MVP (for open source .NET PostgreSQL work)
.NET Core: cross-platform .NET.
MIT license, developed on github.
Microsoft has the most open source contributors on GitHub (Octoverse 2016)
ASP.NET Core in top 10 TechEmpower plaintext benchmark, on Linux.
Introduction
Npgsql Driver Features
Entity Framework Core – O/RM Features for PostgreSQL
Driver/Protocol Internals
Closing Words
Features and Performance
using (var conn = new NpgsqlConnection("Host=localhost;Database=mydatabase;..."))
{
conn.Open();
using (var cmd = new NpgsqlCommand("SELECT 'hello world'", conn))
Console.WriteLine(cmd.ExecuteScalar());
using (var cmd = new NpgsqlCommand("SELECT * FROM foo", conn))
using (var reader = cmd.ExecuteReader())
while (reader.Read())
Console.WriteLine(reader.GetString(0));
}
Layers (e.g. Dapper) make this nicer and more idiomatic
PostgreSQL supports a rich set of non-standard data types:
Domain-specific simple types: inet, macaddr, circle…
Array
Range
Enum
Composite
New types can be added via extensions
var mac = reader.GetFieldValue<PhysicalAddress>(0);
var rng = reader.GetFieldValue<NpgsqlRange<int>(0);
var arr = reader.GetFieldValue<int[]>(0);
// PG: CREATE TYPE mood AS ENUM ('happy', 'sad', 'ok')
enum Mood { Happy, Sad, OK }
NpgsqlConnection.MapEnumGlobally<Mood>();
var mood = reader.GetFieldValue<Mood>(0);
// PG: CREATE TYPE my_composite AS (x int, some_text text)
class MyComposite {
public int x { get; set; }
public string SomeText { get; set; }
}
NpgsqlConnection.MapCompositeGlobally<MyComposite>();
var comp = reader.GetFieldValue<MyComposite>(0);
var cmd = new NpgsqlCommand("UPDATE x SET y=8 WHERE z=9", conn);
cmd.ExecuteNonQuery(); // The thread is stuck
Console.WriteLine("Done");
Unfortunately, async programming usually sucks (NodeJS):
client.connect(function (err) {
if (err) throw err;
// execute a query on our database
client.query('SELECT $1::text as name', ['brianc'], function (err, result) {
if (err) throw err;
// just print the result to the console
console.log(result.rows[0]); // outputs: { name: 'brianc' }
// disconnect the client
client.end(function (err) {
if (err) throw err;
});
});
});
C# supports async operations in the language:
async Task FooAsync() {
var cmd = new NpgsqlCommand("UPDATE x SET y=8 WHERE z=9", conn);
await cmd.ExecuteNonQueryAsync();
Console.WriteLine("Done");
}
In PostgreSQL, preparing statements is important:
SELECT table0.data+table1.data+table2.data+table3.data+table4.data
FROM table0
JOIN table1 ON table1.id=table0.id
JOIN table2 ON table2.id=table1.id
JOIN table3 ON table3.id=table2.id
JOIN table4 ON table4.id=table3.id
Unprepared:
TPS: 953
Prepared:
TPS: 8722
Prepared statements + short-lived connections =
In Npgsql 3.2, prepared statements are persisted:
using (var conn = new NpgsqlConnection(...))
using (var cmd = new NpgsqlCommand("<some_sql>", conn) {
conn.Open();
conn.Prepare();
// The first time on this physical connection, preparation takes place.
// After that, the same prepared statement is reused.
conn.ExecuteNonQuery();
}
Prepared statements + O/RMs =
Npgsql 3.2 includes automatic preparation: all the benefits, no need to call Prepare().
Statement is prepared after being executed 5 times.
We eject least-recently used statements to make room for new ones.
NPGSQL
POSTGRESQL
INSERT INTO...
OK
INSERT INTO...
OK
NPGSQL
POSTGRESQL
INSERT INTO...; INSERT INTO ...
OK; OK
The performance improvement is dramatic.
The further away the server is, the more the speedup (think cloud).
Supported for all CRUD operations, not just insert.
For bulk insert, binary COPY is an even better option.
Entity Framework Core takes advantage of this.
var cmd = new NpgsqlCommand("INSERT INTO ...; INSERT INTO ...", conn);
cmd.ExecuteNonQuery();
Buffer resultsets? Rows? Columns??
JDBC/psycopg2 buffer resultsets by default
Npgsql has fixed send/receive buffers
.NET has API for sequential column access
Read/write should never copy needlessly
Fully binary data transfer
Binary COPY
Waiting for notifications
Kerberos login (Windows/Linux), SSL/TLS
Distributed transactions
Microsoft isn’t the bad guy anymore – full commitment to open-source and cross-platform.
.NET Core is a real option, whatever OS you’re using.
C# (and other .NET languages) is a very modern language that continues to evolve very quickly.
PostgreSQL is fully supported in .NET, Npgsql provides high-performance and feature-rich access.
@shayrojansky
roji@roji.org
https://slides.com/shayrojansky/npgsql-2017-01-tlv