Deterministische MySQL-Verfahren


7

Sollte ich in der Regel alle meine gespeicherten Prozeduren mit dem Schlüsselwort DETERMINISTIC deklarieren, wenn sie tatsächlich deterministisch sind?

Es scheint mir, dass die Mehrheit der gespeicherten Prozeduren deterministisch sein wird. Habe ich Recht, wenn ich denke, dass die einzigen nicht deterministischen Prozeduren solche sind, die nicht deterministische Funktionen wie RAND () oder CURDATE () aufrufen?

Der Grund, den ich frage, ist, dass bei Verwendung der Datenwiederherstellungsfunktion in MySQL Workbench der folgende Fehler angezeigt wird:

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)

Ist es besser, stattdessen einfach 'log_bin_trust_function_creators = 1' zu setzen? Denken Sie daran, dass ich über 50 gespeicherte Prozeduren habe.

Antworten:


6

Es ist sinnvoll, das deterministicSchlüsselwort für Prozeduren zu verwenden, die wirklich deterministisch sind, weil:

Das Deklarieren einer deterministischen Routine als NONDETERMINISTIC kann die Leistung beeinträchtigen, da verfügbare Optimierungen nicht verwendet werden.

Aber:

Habe ich Recht, wenn ich denke, dass die einzigen nicht deterministischen Prozeduren solche sind, die nicht deterministische Funktionen wie RAND () oder CURDATE () aufrufen?

Nein, eine Prozedur, die Daten aus der Datenbank liest und ihr Ergebnis auf diesen Daten (zusätzlich zu ihren Eingaben) basiert, ist ebenfalls nicht deterministisch (da sich diese Daten zwischen Aufrufen ändern können).

Es ist darauf hinzuweisen, dass in einem Replikationskontext berücksichtigt werden muss, ob eine Prozedur DETERMINISTISCH ist oder nicht:

Wenn Sie eine gespeicherte Funktion erstellen, müssen Sie entweder deklarieren, dass sie deterministisch ist oder keine Daten ändert. Andernfalls ist die Datenwiederherstellung oder -replikation möglicherweise nicht sicher.

obwohl:

Wenn zeilenbasierte oder gemischte binäre Protokollierung verwendet wird, wird die Anweisung akzeptiert und repliziert, auch wenn die Funktion ohne das Schlüsselwort DETERMINISTIC definiert wurde.


Das ist völlig falsch und extrem irreführend. Das deterministische Flag bezieht sich auf die Auswirkung, die die Routine auf die Datenbank hat, sodass Routinen, die nur Daten lesen, immer deterministisch sind.
Bikeman868


In dem von Ihnen angegebenen Zitat fehlt ein Schlüsselbegriff, der zu großer Verwirrung geführt hat. Es sollte heißen: "Eine Routine wird als deterministisch angesehen, wenn sie immer das gleiche Ergebnis in der Datenbank für die gleichen Eingabeparameter erzeugt."
Bikeman868

1
Halten Sie inne und überlegen Sie sich eine Minute, warum MySQL möglicherweise wissen muss, ob Ihre Routine unterschiedliche Daten für dieselben Eingaben zurückgibt. Warum sollte es das interessieren? Denken Sie nun an die Tatsache, dass MySQL nur den Routinennamen und die Eingabeparameter in das Replikationsprotokoll schreibt, es sei denn, Sie markieren die Routine als nicht deterministisch. In diesem Fall werden stattdessen alle geänderten Zeilen geschrieben.
Bikeman868

1
Die Dokumente sind nicht gut formuliert und viele Leute sind zu der gleichen Interpretation wie Sie gekommen, daher gibt es viel Verwirrung über dieses Thema. Ich empfehle Ihnen, die Replikation einzurichten und die Protokolldateien zu überprüfen.
Bikeman868

2

log_bin_trust_function_creators

Dies ist einfach ein Ass in der Lücke bei der Migration von gespeicherten Prozeduren. Die DETERMINISTIC-Eigenschaft wurde zu zwei Dingen hinzugefügt:

  • Schützen Sie die Konsistenz der aufgerufenen gespeicherten Prozeduren, die in Binärprotokollen gespeichert sind
  • Sparen Sie Entwicklern die Kopfschmerzen beim Zurückgehen und Hinzufügen der Eigenschaft

Die Fehlermeldung hat einfach ihren hässlichen Kopf aufgerichtet, weil die binäre Protokollierung aktiviert ist und gespeicherte Prozeduren vorhanden sind. Deaktivieren Sie entweder die binäre Protokollierung und markieren Sie die gespeicherten Prozeduren als deterministisch.

Hier ist etwas schnelles und schmutziges, das Sie mit allen gespeicherten Prozeduren tun können, ohne die Skripte bearbeiten zu müssen: Aktualisieren Sie mysql.proc und tun Sie dies:

UPDATE mysql.proc SET is_deterministic = 'YES';

Ich habe es in MySQL 5.5.12 für Windows versucht

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: lwdba@127.0.0.1
    CHARACTER_SET_CLIENT: cp850
    COLLATION_CONNECTION: cp850_general_ci
      DATABASE_COLLATION: latin1_swedish_ci
1 row in set (0.03 sec)

mysql>

Wenn Sie dies für alle gespeicherten Prozeduren tun, sollte MySQL Workbench damit aufhören, sich zu beschweren.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.