サポート » 使い方全般 » ALTER TABLEが大量に実行されてしまう

  • 解決済 itakuraikura

    (@itakuraikura)


    お世話になっております。

    以下my_create_table()でテーブルを作成しました。

    FKのkind_idは、まだwp_kindsテーブルが作成されていないためにコメントアウトし、続くmy_add_fk()で設定するようにしています。

    しかし困ったことが起こりまして、my_add_fk()でALTER TABLEを実行しますと、なぜか大量にFKが追加されてしまいます。

    この問題はどのように回避できますでしょうか?

    // テーブル作成
    my_create_table('yasai');
    function my_create_table( $table_name ) {
    	global $wpdb;
    	require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    
    	$sql = "CREATE TABLE " . $wpdb->prefix . $table_name . "(		
    		post_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT
    		,kind_id INT(2) UNSIGNED NOT NULL
    		,content VARCHAR(10) 
    		,PRIMARY KEY (post_id)
    		#FK設定は対象テーブルがCREATEされる前だったりするので常に my_add_fk() で設定する	
    		#,FOREIGN KEY (kind_id) REFERENCES wp_kinds(kind_id)	
    	);";
    	add_option($table_name."_version", '1.0');
    	dbDelta($sql);
    
    }
    
    // 外部キー追加
    //my_add_fk( 'wp_yasai', 'kind_id', 'wp_kinds', 'kind_id' );
    function my_add_fk($child_table, $child_col, $parent_table, $parent_col){
    	global $wpdb;
    	$wpdb->query("ALTER TABLE $child_table ADD FOREIGN KEY($child_col) REFERENCES $parent_table($parent_col)");
    }
9件の返信を表示中 - 1 - 9件目 (全9件中)
  • こんにちは

    my_add_fk関数の呼び出しが何かの関数の中などではなく PHP ファイルのトップレベルに記述されているので、このプログラムが記述されているファイルが読み込まれるたびに実行されます。

    両方のテーブルが2つとも作られた時点で1度だけ ADD FOREIGN KEY すればいいんじゃないでしょうか。

    トピック投稿者 itakuraikura

    (@itakuraikura)

    こんにちは
    いつもお世話になっております

    >両方のテーブルが2つとも作られた時点で1度だけ ADD FOREIGN KEY すればいいんじゃないでしょうか。

    とのことですが、どのようにすればできますか?次の【A1】と【A2】の二回を、【B1】の一回に変更する、という意味ではないですよね?

    質問では下記【A1】と【A2】という二回のステップに分けてやっていまして、

    【A1】 my_add_fk()をコメントアウトし、my_create_table()を書いた状態でサイトを読み込みテーブル作成を実行
    【A2】my_create_table()をコメントアウトし、my_add_fk()を書いた状態でサイトを読み込みFK設定を実行

    アドバイスを受けて下記【B1】の一回だけにしてみたのですが、やはりFKは複数入ってしまいました。

    【B1】 my_add_fk()とmy_create_table()を書いた状態でサイトを読み込みテーブル作成とFK設定を実行

    トピック投稿者 itakuraikura

    (@itakuraikura)

    また複数がいくつになるかの法則を見つけまして、my_create_table()で設定したカラムの数だけFKが追加される、といった法則でした。

    つまり以下のようにカラムが3つあればFKは3ついった流れです。

    まずは【A1】を実行し、SHOW CREATE TABLE wp_yasai;を実行
    ↓ 結果

    'CREATE TABLE'wp_yasai' (
     'post_id' bigint(20) unsigned NOT NULL AUTO_INCREMENT,
     'kind_id' int(2) unsigned NOT NULL,
     'content' varchar(10) DEFAULT NULL,
     PRIMARY KEY ('post_id')
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8'

    そして【A2】を実行し 、SHOW CREATE TABLE wp_yasai;を実行
    ↓ 結果

    'CREATE TABLE'wp_yasai' (
     'post_id' bigint(20) unsigned NOT NULL AUTO_INCREMENT,
     'kind_id' int(2) unsigned NOT NULL,
     'content' varchar(10) DEFAULT NULL,
     PRIMARY KEY ('post_id'),
     KEY 'kind_id' ('kind_id'),
     CONSTRAINT 'wp_yasai_ibfk_1' FOREIGN KEY ('kind_id') REFERENCES 'wp_kinds' ('kind_id'),
     CONSTRAINT 'wp_yasai_ibfk_2' FOREIGN KEY ('kind_id') REFERENCES 'wp_kinds' ('kind_id'),
     CONSTRAINT 'wp_yasai_ibfk_3' FOREIGN KEY ('kind_id') REFERENCES 'wp_kinds' ('kind_id')
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8'

    ご覧のようにwp_yasai_ibfk_1wp_yasai_ibfk_2wp_yasai_ibfk_3という3つのFKになってしまうのです

    (尚こちらの入力フォームの事情により、上記の結果はバッククオートをアポストロフィーに変換しています。)

    トピック投稿者 itakuraikura

    (@itakuraikura)

    以下のように「FKが設定されていなければ」という条件でもあればと思っているのですが、なかなか検索しても見つけられません…

    function my_add_fk($child_table, $child_col, $parent_table, $parent_col){
    	global $wpdb;
    	if( 「FKが設定されていなければ」 ){
    		$wpdb->query("ALTER TABLE $child_table ADD FOREIGN KEY($child_col) REFERENCES $parent_table($parent_col)");
    	}
    }

    私の書いた意図は、繰り返しになりますがADD FOREIGN KEYに必要なテーブルが両方CREATEされた時点でADD FOREIGN KEYを実行すれば良いということです。
    (この言い方が正確か分かりませんが、2つめのテーブルをCREATEしたときにです)

    CREATE TABLEがいつ実行されるのか、FOREIGN KEY に必要なカラム名はどのように生成されているのかなどのロジックが分からないので、具体的にこういうロジックでやればできるとは言いにくいですが。

    参照する側であれ参照される側であれ、どちらのデータベースをCREATEするときも、それぞれのテーブル名と外部キーに関連したカラム名が決定しているのであれば、CREATE時に他方のデータベースが存在する場合にのみADD FOREIGN KEYすれば良いのではないでしょうか。
    まさか同じテーブルのCREATEを複数回実行はしないと思いますので、ロジック上は1回しかADD FOREIGN KEYされません。

    ロジックがややこしければ、DROP FOREIGN KEYしてからADD FOREIGN KEYすれば1つしか生成されません。
    ただ、追加する度にインデックスを追加するコストがかかりまが、データベースにデータがほとんどなければそのようなコストは無視できると思います。

    ちょっと説明が冗長になってしまいましたが、wp_kindsテーブルが作成されたときにADD FOREIGN KEYすれば良いのではないでしょうか。

    トピック投稿者 itakuraikura

    (@itakuraikura)

    >wp_kindsテーブルが作成されたときにADD FOREIGN KEYすれば良い

    なるほど!わかったかもしれません。
    つまり下記34行目(#ここでwp_yasaiテーブルにFKを追加(※1)のコメントの次の行)でFKをセットするという感じであっていますか?

    // wp_yasaiテーブル作成
    my_create_table('yasai');
    function my_create_table( $table_name ) {
    	global $wpdb;
    	require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    
    	$sql = "CREATE TABLE " . $wpdb->prefix . $table_name . "(		
    		post_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT
    		,kind_id INT(2) UNSIGNED NOT NULL
    		,content VARCHAR(10) 
    		,PRIMARY KEY (post_id)
    		#kindsテーブルのCREATEが終わってから下記を実行するのでここではコメントアウト(※1)
    		#,FOREIGN KEY (kind_id) REFERENCES wp_kinds(kind_id)	
    	);";
    	add_option($table_name."_version", '1.0');
    	dbDelta($sql);
    }
    
    // wp_kindsテーブル作成
    my_create_table('kinds');
    fnction my_create_table( $table_name ) {
    	global $wpdb;
    	require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    
    	$sql = "CREATE TABLE " . $wpdb->prefix . $table_name . "(		
    		kind_id INT(2) UNSIGNED NOT NULL AUTO_INCREMENT
    		,kind    VARCHAR(10) 
    		,PRIMARY KEY (kind_id)	
    	);";
    	add_option($table_name."_version", '1.0');
    	dbDelta($sql);
    	
    	#ここでwp_yasaiテーブルにFKを追加(※1)
    	my_add_fk( 'wp_yasai', 'kind_id', 'wp_kinds', 'kind_id' );
    }
    
    // 外部キー追加
    function my_add_fk($child_table, $child_col, $parent_table, $parent_col){
    	global $wpdb;
    	$wpdb->query("ALTER TABLE $child_table ADD FOREIGN KEY($child_col) REFERENCES $parent_table($parent_col)");
    }
    

    できれば教えて頂きたいのですが、@munyagu 様もこのようにしますか?
    自分なりに12行目のコメントアウトで「FKを別のタイミングで設定します」ということを伝えているつもりですが、やはりタイミングが別だとわかりにくいというか…、でも仕方ないですもんね。何かわかりやすい方法があればいいのですが。

    書かれている処理が書かれている通りのものなのであれば、
    my_create_table('yasai');

    my_create_table('kinds');
    の順番を逆にすれば yasai のCREATE TABLEの SQL 中で外部キーを追加できます。

    しかし、書かれているプログラムが書かれた PHP ファイルがいつ読み込まれるものなのか、何のためにいつ実行されるべきものか分からないので、私ならどう書くかは分かりません。

    トピック投稿者 itakuraikura

    (@itakuraikura)

    たしかにそうですね。
    手掛かりの少ない中でご回答ありがとうございました。
    大変勉強になりました。

9件の返信を表示中 - 1 - 9件目 (全9件中)
  • トピック「ALTER TABLEが大量に実行されてしまう」には新たに返信することはできません。