Implementing Federations inside a new Doctrine Sharding Extension. Some extensions to the DBAL and ORM core have to be done to get this working.
SQL Azure requires one and exactly one clustered index. It makes no difference if the primary key or any other key is the clustered index. Sharding requires an external ID generation (no auto-increment) such as GUIDs. GUIDs have negative properties with regard to clustered index performance, so that typically you would add a "created" timestamp for example that holds the clustered index instead of making the GUID a clustered index.
@@@ php
<?php
use Doctrine\DBAL\DriverManager;
$dbParams = array(
'dbname' => 'tcp:dbname.database.windows.net',
'sharding' => array(
'federationName' => 'Orders_Federation',
'distributionKey' => 'CustID',
'distributionType' => 'integer',
'filteringEnabled' => false,
),
// ...
);
$conn = DriverManager::getConnection($dbParams);
$shardManager = $conn->getShardManager();
// Example 1: query against root database
$sql = "SELECT * FROM Products";
$rows = $conn->executeQuery($sql);
// Example 2: query against the selected shard with CustomerId = 100
$aCustomerID = 100;
$shardManager->selectShard($aCustomerID); // Using Default federationName and distributionKey
// Query: "USE FEDERATION Orders_Federation (CustID = $aCustomerID) WITH RESET, FILTERING OFF;"
$sql = "SELECT * FROM Customers";
$rows = $conn->executeQuery($sql);
// Example 3: Reset API to root database again
$shardManager->selectGlobal();
With sharding all the ids have to be generated for global uniqueness. There are three strategies for this.
The second approach has the benefit of having numerical primary keys, however also a central failure location. The third strategy can seldom be used, because the domains dont allow this. Identity columns cannot be used at all.
@@@ php
<?php
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Id\TableHiLoIdGenerator;
$dbParams = array(
'dbname' => 'dbname.database.windows.net',
// ...
);
$conn = DriverManager::getConnection($dbParams);
$idGenerator = new TableHiLoIdGenerator($conn, 'id_table_name', $multiplicator = 1);
// only once, create this table
$idGenerator->createTable();
$nextId = $idGenerator->generateId('for_table_name');
$nextOtherId = $idGenerator->generateId('for_other_table');
The connection for the table generator has to be a different one than the one used for the main app to avoid transaction clashes.