0

auto_incrementに設定された一意のPK'id'があります。PHPロジックを使用して挿入ごとにインクリメントすることを目的とした英数字フィールド(W1000など)である「label」という2番目のフィールドがあります。

'label'フィールドには、多くのアルファプレフィックスのいずれかがあり、その後に増分番号が続きます。各プレフィックスは個別にインクリメントする必要があります。たとえば、テーブルにW1000とF1123が含まれている場合があります。次のWはW1001になり、次のFはF1124になります。

現在の方法(PHPは最大ラベルを選択し、最大ラベルを挿入+ 1)は競合状態を作成し、時々重複する「ラベル」を取得します。これらの重複した「ラベル」を解決し、このフィールドが一意であることを確認する必要があります。役立つ場合は、プレフィックスと数値を2つのフィールドに分割します。

これを達成するための最良の方法は何ですか?

4

1 に答える 1

1

重複するラベル値の生成を回避するための1つのアプローチは、MyISAMテーブルを使用して一意のシーケンス番号を生成することです。MyISAMは、必要なAUTO_INCREMENTの動作をサポートします。

MySQLリファレンス3.6.9の「MyISAMノート」セクションを参照してください。AUTO_INCREMENTの使用

このアプローチでは、別のMyISAMテーブルを作成します。この表の目的は、一意のシーケンス番号を生成することです。

CREATE TABLE foo 
( prefix  VARHCAR(1) NOT NULL
, num     INT UNSIGNED AUTO_INCREMENT
, PRIMARY KEY (prefix, num)
) Engine=MyISAM

ラベルプレフィックスが1文字で、残りが数値であると仮定します。

INSERT INTO foo (prefix, num)
SELECT SUBSTR(t.label,1,1) AS prefix
     , MAX(SUBSTR(t.label,2,8) AS num
  FROM mytable
 GROUP BY SUBSTR(t.label,1,1)

新しいシーケンス番号を取得し、新しいテーブルに行を挿入して、プレフィックスの値とnum列のNULLを指定し、num列に挿入された値を取得します。

INSERT INTO foo (prefix,num) VALUES ('W',NULL); 
SELECT LAST_INSERT_ID();

labelこれを使用して、元のテーブルの列に使用される値を作成できます。

必要な動作を行うのはMyISAMエンジンのみであることに注意してください(プレフィックスごとにAUTO_INCREMENTシーケンスを個別にインクリメントします)。元のテーブルはどのエンジンでもかまいません。

このアプローチは競合状態を回避しますが、挿入のためにMyISAMテーブルで排他的ロックが取られるため、同時実行のボトルネックが発生します。


競合状態を回避するもう1つの方法は、テーブルの排他ロックを取得してからSELECT MAX()を実行し、次に挿入を実行してからロックを解除することです。しかし、そのアプローチでは、同時実行のボトルネックがさらに発生し、単一のリソースへのアクセスがシリアル化されます。


質問が既存の重複label値の識別に関するものである場合、このクエリは「重複」ラベルを持つ行を取得します。(これは、複製されたラベルごとに1行だけを選択します。)

SELECT t.label
     , MAX(t.id)
  FROM mytable t
 GROUP BY t.label
HAVING COUNT(1) > 1

ラベルを一意に更新するには、それらの行の新しいラベルを生成する必要があります。

単一のSQLステートメントでそれを実行するのは少し注意が必要です。私は声明を考え出そうとしましたが、それは壊れていて、それを修正する時間がありません。

于 2013-03-25T02:33:17.240 に答える