symfony2のmariadbでのdoctrineスキーマ関連のコマンドが劇遅

doctrine:schema:update , doctrine:migrations:migrateのコマンドが恐ろしく遅かったので原因を調べました。

どうやら Doctrine\DBAL\Schema\AbstractSchemaManagerlistTableForeignKeys 内で実行される information_schema.key_column_usage テーブルへの参照が恐ろしく遅い様子。mariaDBのバグ?それともMySQL時代からあるんだろうか。自分の環境では全DB内で1000以上のテーブルが存在しているので、おそらくそのせいか…
とりあえずカスタムドライバとカスタムスキーママネージャを作って対処することに。

Doctrine DBALカスタムドライバの作り方

こちらのリンク を参考にして作ってみます。
今回はCustomDoctrineというバンドルを作り、その中にドライバとスキーママネージャを作成します。

Driverクラス

 
<?php
 
namespace CustomDoctrine\DBAL\Driver\CustomPdoMysql;
 
 
use Doctrine\DBAL\Connection;
use CustomDoctrine\DBAL\Schema\CustomMysqlSchemaManager;
 
/**
 * PDO MySql driver.
 *
 * @since 2.0
 */
class Driver extends \Doctrine\DBAL\Driver\PDOMySql\Driver
{
 
    public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
    {
        return new CustomMysqlSchemaManager($conn);
    }
}
 

SchemaManagerクラス

ここが肝心の処理部分。show create tableから取り出すことにしました。

 
<?php
 
namespace CustomDoctrine\DBAL\Schema;
 
use Doctrine\DBAL\Schema\MySqlSchemaManager;
 
class CustomMysqlSchemaManager extends MySqlSchemaManager {
	public function listTableForeignKeys($table, $database = null) {
		if (is_null ( $database )) {
			$database = $this->_conn->getDatabase ();
		}
		$sql = "show create table {$table}";
		$results = $this->_conn->fetchAll($sql);
		$tableForeignKeys = array();
 
		foreach($results as $val)
		{
			$matches = array();
 
			preg_match_all(
				"/CONSTRAINT `([^`]+)` FOREIGN KEY \(`([^`]+)`\) REFERENCES `([^`]+)` \(`([^`]+)`\)[\s]*(.*)/",
				$val['Create Table'], $matches);
			foreach($matches[0] as $key => $match)
			{
				$v = array();
				$v['constraint_name'] = $matches[1][$key];
				$v['column_name'] = $matches[2][$key];
				$v['referenced_table_name'] = $matches[3][$key];
				$v['referenced_column_name']= $matches[4][$key];
				$v['delete_rule'] = null;
				$v['update_rule'] = null;
				$frules = explode("ON ",
						str_replace(",", "",$matches[5][$key])
				);
				foreach($frules as $rule)
				{
					$rule = preg_replace("/(.*)[\s]+$/", "$1", $rule);
					if(preg_match("/DELETE/", $rule))
					{
						$v['delete_rule'] = str_replace("DELETE ", "", $rule);
					}
					if(preg_match("/UPDATE/", $rule))
					{
						$v['update_rule'] = str_replace("UPDATE ", "", $rule);
					}
				}
				$tableForeignKeys[] = $v;
			}
		}
		print_r($tableForeignKeys);
 
		return $this->_getPortableTableForeignKeysList ( $tableForeignKeys );
	}
}
 

config.ymlの編集

app/config/config.yml 内を以下のように変更する。 driver_class 属性でDriverを指定すると、適用されるみたいです。

 
doctrine:
    dbal:
        driver:   %database_driver%
        driver_class: CustomDoctrine\DBAL\Driver\CustomPdoMysql\Driver