web-dev-qa-db-ja.com

MySQLの確定的手順

原則として、すべてのストアドプロシージャが実際に決定的である場合、それらをDETERMINISTICキーワードで宣言する必要がありますか?

ストアドプロシージャの大部分は確定的であるように思えます。非決定的なプロシージャはRand()やCURDATE()などの非決定的な関数を呼び出すものだけだと私は思いますか?

とにかく、私が尋ねている理由は、MySQL Workbench内でデータ復元機能を使用すると、次のエラーが発生するためです。

ERROR 1418 (HY000) at line 1209: This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)

代わりに単に「log_bin_trust_function_creators = 1」を設定する方が良いでしょうか? 50以上のストアドプロシージャがあることに注意してください。

7
David

次の理由により、実際に決定論的であるプロシージャに対してdeterministicキーワードを使用することには意味があります。

確定的ルーチンをNONDETERMINISTICとして宣言すると、使用可能な最適化が使用されなくなるため、パフォーマンスが低下する可能性があります。

だが:

非決定的な手続きはRand()やCURDATE()のような非決定的な関数を呼び出すものだけだと私は思いますか?

いいえ、データベースからデータを読み取り、その結果に基づいて(その入力に加えて)データを基にするプロシージャも非決定的です(呼び出し間でデータが変わる可能性があるため)。

プロシージャが決定的であるかどうかは、レプリケーションのコンテキストで考慮する必要があることを指摘する価値があります。

ストアドファンクションを作成するときは、確定的であること、またはデータを変更しないことを宣言する必要があります。それ以外の場合は、データの回復またはレプリケーションにとって安全ではない可能性があります。

ただし:

行ベースまたは混合バイナリー・ロギングが使用されている場合、関数がDETERMINISTICキーワードなしで定義されていても、ステートメントは受け入れられ、複製されます。

log_bin_trust_function_creators

これは、ストアドプロシージャを移行する際の穴のエースです。 DETERMINISTICプロパティが次の2つに追加されました。

  • バイナリログに保存されている呼び出されたストアドプロシージャの一貫性を保護する
  • 戻ってプロパティを追加するという開発者の頭痛を軽減します

バイナリロギングが有効になっていて、ストアドプロシージャが存在するため、エラーメッセージは単に醜い頭を抱えています。バイナリロギングを無効にするか、ストアドプロシージャを確定的としてマークします。

スクリプトを編集せずに、すべてのストアドプロシージャに対して簡単にできることを以下に示します。mysql.procを更新して、これを実行します。

UPDATE mysql.proc SET is_deterministic = 'YES';

MySQL 5.5.12 for Windowsで試してみました

mysql> select db,name from mysql.proc;
+--------+-----------------------+
| db     | name                  |
+--------+-----------------------+
| lovesh | LoadMyData            |
| stuff  | DoesUserHaveEditPrivs |
| stuff  | LoadSampleData        |
| stuff  | MakeTables            |
| stuff  | ShowLast40            |
| test   | CreateSampleTable     |
| test   | CreateSampleTables    |
| test   | GetMissingIntegers    |
| test   | GetTestTableCounts    |
| test   | ImportWeeklyBatch     |
| test   | InsertName            |
| test   | LoadSampleTables      |
| test   | MigrateColumn         |
+--------+-----------------------+
13 rows in set (0.00 sec)

mysql> select db,name,is_deterministic from mysql.proc ;
+--------+-----------------------+------------------+
| db     | name                  | is_deterministic |
+--------+-----------------------+------------------+
| test   | InsertName            | NO               |
| test   | MigrateColumn         | NO               |
| test   | GetMissingIntegers    | NO               |
| test   | CreateSampleTable     | NO               |
| test   | CreateSampleTables    | NO               |
| test   | LoadSampleTables      | NO               |
| test   | ImportWeeklyBatch     | NO               |
| test   | GetTestTableCounts    | NO               |
| stuff  | MakeTables            | NO               |
| stuff  | ShowLast40            | NO               |
| stuff  | LoadSampleData        | NO               |
| stuff  | DoesUserHaveEditPrivs | NO               |
| lovesh | LoadMyData            | NO               |
+--------+-----------------------+------------------+
13 rows in set (0.00 sec)

mysql> update mysql.proc set is_deterministic='YES' where db='lovesh';
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select db,name,is_deterministic from mysql.proc ;
+--------+-----------------------+------------------+
| db     | name                  | is_deterministic |
+--------+-----------------------+------------------+
| test   | InsertName            | NO               |
| test   | MigrateColumn         | NO               |
| test   | GetMissingIntegers    | NO               |
| test   | CreateSampleTable     | NO               |
| test   | CreateSampleTables    | NO               |
| test   | LoadSampleTables      | NO               |
| test   | ImportWeeklyBatch     | NO               |
| test   | GetTestTableCounts    | NO               |
| stuff  | MakeTables            | NO               |
| stuff  | ShowLast40            | NO               |
| stuff  | LoadSampleData        | NO               |
| stuff  | DoesUserHaveEditPrivs | NO               |
| lovesh | LoadMyData            | YES              |
+--------+-----------------------+------------------+
13 rows in set (0.00 sec)

mysql> desc information_schema.routines;
+--------------------------+---------------+------+-----+---------------------+-------+
| Field                    | Type          | Null | Key | Default             | Extra |
+--------------------------+---------------+------+-----+---------------------+-------+
| SPECIFIC_NAME            | varchar(64)   | NO   |     |                     |       |
| ROUTINE_CATALOG          | varchar(512)  | NO   |     |                     |       |
| ROUTINE_SCHEMA           | varchar(64)   | NO   |     |                     |       |
| ROUTINE_NAME             | varchar(64)   | NO   |     |                     |       |
| ROUTINE_TYPE             | varchar(9)    | NO   |     |                     |       |
| DATA_TYPE                | varchar(64)   | NO   |     |                     |       |
| CHARACTER_MAXIMUM_LENGTH | int(21)       | YES  |     | NULL                |       |
| CHARACTER_OCTET_LENGTH   | int(21)       | YES  |     | NULL                |       |
| NUMERIC_PRECISION        | int(21)       | YES  |     | NULL                |       |
| NUMERIC_SCALE            | int(21)       | YES  |     | NULL                |       |
| CHARACTER_SET_NAME       | varchar(64)   | YES  |     | NULL                |       |
| COLLATION_NAME           | varchar(64)   | YES  |     | NULL                |       |
| DTD_IDENTIFIER           | longtext      | YES  |     | NULL                |       |
| ROUTINE_BODY             | varchar(8)    | NO   |     |                     |       |
| ROUTINE_DEFINITION       | longtext      | YES  |     | NULL                |       |
| EXTERNAL_NAME            | varchar(64)   | YES  |     | NULL                |       |
| EXTERNAL_LANGUAGE        | varchar(64)   | YES  |     | NULL                |       |
| PARAMETER_STYLE          | varchar(8)    | NO   |     |                     |       |
| IS_DETERMINISTIC         | varchar(3)    | NO   |     |                     |       |
| SQL_DATA_ACCESS          | varchar(64)   | NO   |     |                     |       |
| SQL_PATH                 | varchar(64)   | YES  |     | NULL                |       |
| SECURITY_TYPE            | varchar(7)    | NO   |     |                     |       |
| CREATED                  | datetime      | NO   |     | 0000-00-00 00:00:00 |       |
| LAST_ALTERED             | datetime      | NO   |     | 0000-00-00 00:00:00 |       |
| SQL_MODE                 | varchar(8192) | NO   |     |                     |       |
| ROUTINE_COMMENT          | longtext      | NO   |     | NULL                |       |
| DEFINER                  | varchar(77)   | NO   |     |                     |       |
| CHARACTER_SET_CLIENT     | varchar(32)   | NO   |     |                     |       |
| COLLATION_CONNECTION     | varchar(32)   | NO   |     |                     |       |
| DATABASE_COLLATION       | varchar(32)   | NO   |     |                     |       |
+--------------------------+---------------+------+-----+---------------------+-------+
30 rows in set (0.02 sec)

mysql> select * from information_schema.routines where routine_schema='lovesh'\G
*************************** 1. row ***************************
           SPECIFIC_NAME: LoadMyData
         ROUTINE_CATALOG: def
          ROUTINE_SCHEMA: lovesh
            ROUTINE_NAME: LoadMyData
            ROUTINE_TYPE: PROCEDURE
               DATA_TYPE:
CHARACTER_MAXIMUM_LENGTH: NULL
  CHARACTER_OCTET_LENGTH: NULL
       NUMERIC_PRECISION: NULL
           NUMERIC_SCALE: NULL
      CHARACTER_SET_NAME: NULL
          COLLATION_NAME: NULL
          DTD_IDENTIFIER: NULL
            ROUTINE_BODY: SQL
      ROUTINE_DEFINITION: BEGIN
    DECLARE NDX INT;
    SET NDX = 0;
    WHILE NDX < 100 DO
        INSERT INTO mydata (ti_time) VALUES (NOW() - INTERVAL CEILING(14400*Rand()) SECOND
);
        SET NDX = NDX + 1;
    END WHILE;
END
           EXTERNAL_NAME: NULL
       EXTERNAL_LANGUAGE: NULL
         PARAMETER_STYLE: SQL
        IS_DETERMINISTIC: YES
         SQL_DATA_ACCESS: CONTAINS SQL
                SQL_PATH: NULL
           SECURITY_TYPE: DEFINER
                 CREATED: 2011-07-25 11:12:02
            LAST_ALTERED: 2011-07-18 22:39:34
                SQL_MODE:
         ROUTINE_COMMENT:
                 DEFINER: [email protected]
    CHARACTER_SET_CLIENT: cp850
    COLLATION_CONNECTION: cp850_general_ci
      DATABASE_COLLATION: latin1_swedish_ci
1 row in set (0.03 sec)

mysql>

すべてのストアドプロシージャに対してこれを行うと、MySQL Workbenchは文句を言わなくなります。

2
RolandoMySQLDBA