Thủ tục xác định MySQL


7

Theo nguyên tắc chung, tôi có nên khai báo tất cả các thủ tục được lưu trữ của mình bằng từ khóa DETERMINISTIC nếu chúng thực sự mang tính quyết định?

Dường như với tôi rằng phần lớn các thủ tục được lưu trữ sẽ mang tính quyết định. Tôi có đúng không khi nghĩ rằng các thủ tục không xác định duy nhất là các thủ tục gọi các hàm không xác định như RAND () hoặc CURDATE ()?

Dù sao, lý do tôi hỏi là vì khi tôi sử dụng tính năng Khôi phục dữ liệu trong MySQL Workbench, tôi gặp lỗi này:

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)

Có phải thực tế tốt hơn là chỉ cần đặt 'log_bin_trust_feft_creators = 1' thay vào đó? Hãy nhớ rằng tôi có hơn 50 thủ tục được lưu trữ.

Câu trả lời:


6

Thật hợp lý khi sử dụng deterministictừ khóa cho các thủ tục thực sự mang tính quyết định, bởi vì:

Tuyên bố một thói quen xác định là NONDETERMINISTIC có thể làm giảm hiệu suất bằng cách khiến tối ưu hóa có sẵn không được sử dụng.

Nhưng:

Tôi có đúng không khi nghĩ rằng các thủ tục không xác định duy nhất là các thủ tục gọi các hàm không xác định như RAND () hoặc CURDATE ()?

Không, một quy trình đọc dữ liệu từ cơ sở dữ liệu và dựa trên dữ liệu đó (ngoài các đầu vào của nó) cũng không mang tính quyết định (vì dữ liệu đó có thể thay đổi giữa các cuộc gọi).

Cần chỉ ra rằng liệu một thủ tục có XÁC ĐỊNH hay không cần phải được xem xét trong bối cảnh nhân rộng:

Khi bạn tạo một hàm được lưu trữ, bạn phải khai báo rằng nó có tính xác định hoặc nó không sửa đổi dữ liệu. Mặt khác, nó có thể không an toàn để phục hồi hoặc sao chép dữ liệu.

Mặc du:

Nếu ghi nhật ký nhị phân dựa trên hàng hoặc hỗn hợp được sử dụng, câu lệnh được chấp nhận và sao chép ngay cả khi hàm được xác định mà không có từ khóa DETERMINISTIC.


Điều này là hoàn toàn sai lầm và cực kỳ sai lệch. Cờ xác định đề cập đến hiệu ứng của thường trình trên cơ sở dữ liệu, vì vậy các thường trình chỉ đọc dữ liệu luôn mang tính xác định.
bikeman868


Các trích dẫn bạn đưa ra là thiếu một cụm từ quan trọng đã dẫn đến nhiều nhầm lẫn. Nó nên nói ra Một thói quen được coi là xác định nếu nó luôn tạo ra cùng một kết quả trong cơ sở dữ liệu cho cùng một tham số đầu vào.
bikeman868

1
Dừng lại và suy nghĩ một phút về lý do tại sao MySQL có thể cần biết nếu thói quen của bạn trả về dữ liệu khác nhau cho cùng một đầu vào, tại sao nó lại quan tâm? Bây giờ hãy nghĩ về thực tế rằng MySQL chỉ ghi tên thường trình và các tham số đầu vào trong nhật ký sao chép trừ khi bạn đánh dấu thường trình là không xác định trong trường hợp nó ghi tất cả các hàng thay đổi.
bikeman868

1
Các tài liệu không được thực hiện tốt và nhiều người đã đến cùng một cách giải thích như bạn, vì vậy có nhiều nhầm lẫn về chủ đề này. Tôi khuyến khích bạn thiết lập sao chép và kiểm tra các tệp nhật ký.
bikeman868

2

log_bin_trust_feft_creators

Đây chỉ đơn giản là một con át chủ bài khi di chuyển Thủ tục lưu trữ. Thuộc tính DETERMINISTIC đã được thêm vào hai điều:

  • Bảo vệ tính nhất quán của các thủ tục được lưu trữ được lưu trữ trong nhật ký nhị phân
  • Lưu các nhà phát triển đau đầu của việc quay lại và thêm tài sản

Thông báo lỗi chỉ đơn giản là nuôi cái đầu xấu xí của nó vì đăng nhập nhị phân được kích hoạt và có các thủ tục được lưu trữ. Hoặc vô hiệu hóa ghi nhật ký nhị phân, đánh dấu các thủ tục được lưu trữ là xác định.

Đây là một cái gì đó nhanh và bẩn bạn có thể làm với tất cả các thủ tục được lưu trữ mà không cần phải chỉnh sửa các tập lệnh: Cập nhật mysql.proc và làm điều này:

UPDATE mysql.proc SET is_deterministic = 'YES';

Tôi đã thử nó trên một trong MySQL 5.5.12 cho 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: 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>

Nếu bạn làm điều này với tất cả các thủ tục được lưu trữ, điều này sẽ khiến MySQL Workbench ngừng phàn nàn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.