I have some sharded tables in a MySQL environment. I use Yii so I wanted to add some support for the sharding. I have managed to make a custom CActiveRecord class that is mother to all the sharded models:
class ShardedActiveRecord extends CActiveRecord{
private $_shard;
public function tableName(){
return get_class($this) . $this->getShard();
}
public function setShard($shard) {
$this->_shard = $shard;
call_user_func(array(get_class($this), 'model'))->_shard = $shard;
$this->refreshMetaData();
return $this;
}
public function getShard() {
if($this->_shard === null){
$this->setShard("");
}
return $this->_shard;
}
public function createShardedTable($shard){
$connection=Yii::app()->db;
$command = $connection->createCommand("CREATE TABLE IF NOT EXISTS ".get_class($this).$shard." LIKE ".get_class($this));
$command->execute();
}
}
Everything works fine on insert, but when I need to retrieve some data, I don't know how to proceed. I would like in my model to have a parameter that would be the sharded tables to unite. Here is an example of what I would like to be possible:
MyModel::model()->shard("01,"02",03")->findAll();
And eventually that to return the last 3 tables:
$data = new CActiveDataProvider("MyModel")
The sql for retrieving the data shoold look like this if I want to select the first 3 tables:
SELECT * FROM stats01
UNION SELECT * FROM stats02
UNION SELECT * FROM stats03
I have tried to redefine the fetchData() function but it didn't work, the redefined function was not altering the dataset... I need to have all the datas as one big chunk as if it was a single table.
Thank you!
Update:
I found a solution to the problem. I created a function in my ShardedActiveRecord class that generates a custom CActiveRecord and returns it. Here is how it looks:
public function getMergedDataProvider($back){
$modelArray = array();
$model = array();
$now = date("Ym");
for($i=0; $i<$back; $i++){
array_push($modelArray, $this->model()->setShard(date("Ym", strtotime("-".$i." month", strtotime($now))))->findAll());
}
foreach($modelArray as $ma){
$model = array_merge($model, $ma);
}
$dataProvider = new CActiveDataProvider(get_class($this), array(
'data'=>$model,
));
return $dataProvider;
}
I added a parameter that will allow me to go get the last 3 table shards (they are relative to a date).
In an action that requires the use of a sharded model, I can call the function as so, and use it as a normal CActiveDataProvider:
$dataProvider = MyModel::model()->getMergedDataProvider(3);
I hope this will help someone!