介紹
Yii2 Framework對Database的操作有非常良好的結構彈性,供開發者從底層到Object-Oriented自行評估選用。
這裡對Yii2 Database定義了三層設計模式:SQL Command、Query builder、Active Record(ORM)
其中效能差異在於Active Record(ORM)設計模式,
範例程式碼
SQL Command Level
# Get DB componet of Application
$db = Yii::$app->db;
# Get data form SQL execution
$arrayData = $db->createCommand('SELECT * FROM table limit 10')
->queryAll();
print_r($arrayData);
Query Builder Level
$arrayData = (new \yii\db\Query())
->select(['*'])
->from('table')
->where([])
->limit(10)
->all();
print_r($arrayData);
除了Build to SQL處理外,尚會多一次資料O(f(n))處理,應用如
indexBy()
。
Active Record (ORM)
$ojectData = \app\models\ActiveRecordModal::find()
->select(['*'])
->where([])
->limit(10)
->all();
print_r($ojectData);
Raw SQL 語句查看
SQL Command本身:yii\db\Command
為Query builder、Active Record之基底。
提供$rawSql
原始SQL語句變數,所以在生成SQL Command(createCommand()
)後使用。
$sql= Yii::$app->db->createCommand('SELECT * FROM table limit 10')
->rawSql;
echo $sql;
$sql= (new \yii\db\Query())
->select(['*'])
->from('table')
->where([])
->limit(10)
->createCommand()->rawSql; //Create Command
echo $sql;
$sql= \app\models\ActiveRecordModal::find()
->select(['*'])
->where([])
->limit(10)
->createCommand()->rawSql; //Create Command
echo $sql;
AR效能優化
SQL Command與Query builder之間的O(f(n))差異基本上沒甚麼瓶頸,
主要亮點在於Active Record因為ORM實現出現效能損耗,包含ORM記憶體與DB Connection數量會多發來做欄位查詢,所以如果想保留AR操作設計模式但不使用ORM,以下為優化方法:
-
Active Record使用
asArray()
即會略過ORM處理,回傳資料由物件變回陣列,達到Builder Level效能://Skip ORM, return to builder level $arrayData = \app\models\ActiveRecordModal::find() ->asArray() ->all(); print_r($arrayData);
損失AR(ORM) Level功能
-
Active Record也可以轉回為SQL Command基底操作,達到SQL Command Level效能:
$arrayData = \app\models\ActiveRecordModal::find() ->createCommand() //Using SQL Command level without ORM ->queryAll(); print_r($arrayData);
損失AR(ORM) Level & Builder Level功能
SQL Command Level與Query Builder Level之間運算與記憶體微差,如沒有用到Builder功能如
indexBy()
則可評估轉回。
你好
有個問題想請教你
在 yii 有什麼方法, 可以切換到另一個資料庫? 類似codeigniter 裡this->load->dbforge() 直接切換到另一個資料庫, 不用再做另一個資料庫連接的配置
Eric
Hi,
Yii2可以設定多組DB Config,讓每個ActiveRecord透過`getDb()`來設定對應的DB。
如果你要同一個DB Connection做DB切換,在相同的Permission下做Prefix資料庫選定即可,如`database2.table1`。
勵害 !
謝謝