Question

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!

Was it helpful?

Solution

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!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top