Details
-
New Feature
-
Status: In Review (View Workflow)
-
Critical
-
Resolution: Unresolved
Description
Currently, only the InnoDB storage engine is storing information about FOREIGN KEY constraints. The metadata is stored in two hidden tables that are only accessible to InnoDB. The tables are created in the InnoDB internal SQL parser as follows:
CREATE TABLE SYS_FOREIGN(ID CHAR, FOR_NAME CHAR, REF_NAME CHAR, N_COLS INT); |
CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN (ID); |
CREATE INDEX FOR_IND ON SYS_FOREIGN (FOR_NAME); |
CREATE INDEX REF_IND ON SYS_FOREIGN (REF_NAME); |
|
CREATE TABLE SYS_FOREIGN_COLS(ID CHAR, POS INT, FOR_COL_NAME CHAR, REF_COL_NAME CHAR); |
CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS); |
It is a bad idea to identify the tables and columns by names, because it forces InnoDB to update these tables when tables or columns are renamed. Furthermore, the names are stored and sorted as if they were encoded in latin1_swedish_ci, while they should really have been handled as utf8_unicode_ci (system_charset_info).
The SYS_FOREIGN.ID consists of the schema name and a user-specified constraint name. If no constraint name is specified by the user, then it will be generated like childtablename_ibfk_1, childtablename_ibfk_2, and so on. The ID must be unique within the database.
In main memory, InnoDB stores the foreign key metadata in a data structure dict_foreign_t. This structure stores both table names and table pointers. Tables that are attached to foreign key constraints cannot be evicted from the InnoDB table cache. The reason for this is that whenever a table that is attached to a foreign key constraint is modified, we may have to read or modify records in other tables.
As part of this task, the FOREIGN KEY metadata would be stored in the SQL layer. A natural place could be the .frm file. Alas, if we only stored the information in the .frm file of one of the tables that are part of the constraint, then we would have to read all .frm files before any table can be modified, because we must be aware of all tables that the current table REFERENCES to or that are pointing to the current table by REFERENCES clauses.
If we stored the FOREIGN KEY metadata in the .frm files of both the child and the parent tables, then RENAME TABLE would have to update a large number of .frm files in an atomic and crash-safe fashion. This would require transactional logging, which is currently missing.
Proposal: Store FOREIGN KEY Constraints in .frk Files
It would seem simplest to introduce a new type of files for storing FOREIGN KEY constraints. All these files would be read at startup, and all .frm files pointed to by them would be opened. If there is a mismatch (say, one or both of the tables does not exist, or column names or types do not match, or the columns are not covered by appropriate indexes), a warning would be issued to the server error log, and the constraint would be ignored.
Columns that are part of the constraint could be identified either by name or by position in the SHOW CREATE TABLE output. Position could be preferred, because the .frk files would not have to be updated when renaming columns. But, then they would have to be updated when dropping, adding or reordering columns.
Updates of the .frk files must not only be crash-safe, but transactional and atomic together with updates of .frm files and the storage engine data. This will require some form of logging that is synchronized with InnoDB transaction commit, also when it happens inside ha_innobase::commit_inplace_alter_table().
Option: constraintname.frk (one REFERENCES clause per file)
Each constraintname.frk file would have to contain both the child and parent table names, and identify the participating columns.
We would potentially have a very large number of files, and many of them would have to be atomically and transactionally updated in RENAME TABLE.
Option: childtablename.frk (multiple REFERENCES clauses per file)
The child table name would be implied by the file name; only the parent table names would be stored in the file, along with the identities of the columns. The uniqueness of constraint identifiers would be enforced in memory only. (We have to keep all foreign key constraints in memory anyway.)
RENAME TABLE of a child table would only have to transactionally rename childtablename.frk and childtablename.frm. Renaming a parent table will have to transactionally rewrite the childtablename.frk to update the REFERENCES clauses.
With childtablename.frk files (and assuming that the InnoDB internal data dictionary will some day be removed in MDEV-11655), users could manually rename child tables by renaming files, but renaming parent tables would still require editing the .frk file. We might consider using an editing-friendly file format. In that case, the transactional logging and crash recovery for .frk file operations must be made as robust as possible.
Attachments
Issue Links
- blocks
-
MDEV-12094 Foreign key meta-data for MyISAM
-
- Open
-
-
MDEV-12483 Add foreign keys support for partitioned tables
-
- Stalled
-
-
MDEV-22361 Cross-engine foreign keys support
-
- Open
-
- includes
-
MDEV-20865 Store foreign key info in FRM and TABLE_SHARE
-
- In Review
-
- is blocked by
-
MDEV-17567 Atomic DDL
-
- Closed
-
-
MDEV-20480 Obsolete internal parser for FK in InnoDB
-
- Closed
-
-
MDEV-23549 CREATE fails after DROP without FRM
-
- Closed
-
-
MDEV-23554 Wrong default value for foreign_key_checks variable
-
- Closed
-
-
MDEV-25180 Atomic ALTER TABLE
-
- Closed
-
-
MDEV-27180 Fully atomic partitioning DDL operations
-
- In Review
-
- is part of
-
MDEV-12483 Add foreign keys support for partitioned tables
-
- Stalled
-
- relates to
-
MDEV-11412 Ensure that table is truly dropped when using DROP TABLE
-
- Closed
-
-
MDEV-21964 Case of referenced column of foreign key not corrected on import
-
- Open
-
-
MDEV-22180 Planner opens unnecessary tables when updated table is referenced by foreign keys
-
- Closed
-
-
MDEV-22602 WITHOUT OVERLAPS constraint is ignored when update is performed via foreign key cascade
-
- Closed
-
-
MDEV-25935 Misleading error message due to FOREIGN KEY on RENAME TABLE
-
- Open
-
-
MDEV-30416 Can't redefine constraint in a single ALTER TABLE
-
- Confirmed
-
-
MDEV-35303 Store foreign keys, even not supported
-
- Closed
-
-
MDEV-10393 Foreign keys SET DEFAULT action
-
- Open
-
-
MDEV-17123 Impossible to drop primary key in certain circumstances
-
- Open
-
-
MDEV-19402 Invoke triggers for foreign key cascade actions
-
- Closed
-
-
MDEV-19453 FK errors are hidden behind an obscure command
-
- Open
-
-
MDEV-23455 Hangs + Sig11 in unknown location(s) due to single complex FK query
-
- Closed
-
-
MDEV-25885 Rename table operation using copy algorithm fails to rename the foreign key constraint
-
- Stalled
-
Activity
Field | Original Value | New Value |
---|---|---|
Epic Link | PT-77 [ 68558 ] |
Description |
Currently, only the InnoDB storage engine is storing information about
{{FOREIGN KEY}} constraints. The metadata is stored in two hidden tables that are only accessible to InnoDB. The tables are created in the InnoDB internal SQL parser as follows: {code:sql} CREATE TABLE SYS_FOREIGN(ID CHAR, FOR_NAME CHAR, REF_NAME CHAR, N_COLS INT); CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN (ID); CREATE INDEX FOR_IND ON SYS_FOREIGN (FOR_NAME); CREATE INDEX REF_IND ON SYS_FOREIGN (REF_NAME); CREATE TABLE SYS_FOREIGN_COLS(ID CHAR, POS INT, FOR_COL_NAME CHAR, REF_COL_NAME CHAR); CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS); {code} It is a bad idea to identify the tables and columns by names, because it forces InnoDB to update these tables when tables or columns are renamed. Furthermore, the names are stored and sorted as if they were encoded in {{latin1_swedish_ci}}, while they should really have been handled as {{utf8_unicode_ci}} ({{system_charset_info}}). The {{SYS_FOREIGN.ID}} consists of the schema name and a user-specified constraint name. If no constraint name is specified by the user, then it will be generated like {{childtablename_ibfk_1}}, {{childtablename_ibfk_2}}, and so on. The {{ID}} must be unique within the database. In main memory, InnoDB stores the foreign key metadata in a data structure {{dict_foreign_t}}. This structure stores both table names and table pointers. Tables that are attached to foreign key constraints cannot be evicted from the InnoDB table cache. The reason for this is that whenever a table that is attached to a foreign key constraint is modified, we may have to read or modify records in other tables. As part of this task, the {{FOREIGN KEY}} metadata would be stored in the SQL layer. A natural place could be the {{.frm}} file. Alas, if we only stored the information in the {{.frm}} file of one of the tables that are part of the constraint, then we would have to read all {{.frm}} files before any table can be modified, because we must be aware of all tables that the current table {{REFERENCES}} to or that are pointing to the current table by {{REFERENCES}} clauses. If we stored the {{FOREIGN KEY}} metadata in the {{.frm}} files of both the child and the parent tables, then {{RENAME TABLE}} would have to update a large number of {{.frm}} files in an atomic and crash-safe fashion. This would require transactional logging, which is currently missing. h2. Proposal: Store {{FOREIGN KEY}} Constraints in {{.frk}} Files It would seem simplest to introduce a new type of files for storing {{FOREIGN KEY}} constraints. All these files would be read at startup, and all {{.frm}} files pointed to by them would be opened. If there is a mismatch (say, one or both of the tables does not exist, or column names or types do not match, or the columns are not covered by appropriate indexes), a warning would be issued to the server error log, and the constraint would be ignored. Columns that are part of the constraint could be identified either by name or by position in the {{SHOW CREATE TABLE}} output. Position could be preferred, because the {{.frk}} files would not have to be updated when renaming columns. But, then they would have to be updated when dropping, adding or reordering columns. Updates of the {{.frk}} files must not only be crash-safe, but transactional and atomic together with updates of {{.frm}} files and the storage engine data. This will require some form of logging that is synchronized with InnoDB transaction commit, also when it happens inside {{ha_innobase::commit_inplace_alter_table()}}. h3. Option: {{constraintname.frk}} (one {{REFERENCES}} clause per file) Each {{constraintname.frk}} file would have to contain both the child and parent table names, and identify the participating columns. We would potentially have a very large number of files, and many of them would have to be atomically and transactionally updated in {{RENAME TABLE}}. h3. Option: {{childtablename.frk}} (multiple {{REFERENCES}} clauses per file) The child table name would be implied by the file name; only the parent table names would be stored in the file, along with the identities of the columns. The uniqueness of constraint identifiers would be enforced in memory only. (We have to keep all foreign key constraints in memory anyway.) {{RENAME TABLE}} of a child table would only have to transactionally rename {{childtablename.frk}} and {{childtablename.frm}}. Renaming a parent table will have to transactionally rewrite the {{childtablename.frk}} to update the {{REFERENCES}} clauses. With {{childtablename.frk}} files (and assuming that the InnoDB internal data dictionary will some day be removed in MDEV-11655), users could manually rename child tables by renaming files, but renaming parent tables would still require editing the {{.frk}} file. We might consider using an editing-friendly file format. In that case, the transactional logging and crash recovery for {{.frk}} file operations must be made as robust as possible. |
Description |
Currently, only the InnoDB storage engine is storing information about
{{FOREIGN KEY}} constraints. The metadata is stored in two hidden tables that are only accessible to InnoDB. The tables are created in the InnoDB internal SQL parser as follows: {code:sql} CREATE TABLE SYS_FOREIGN(ID CHAR, FOR_NAME CHAR, REF_NAME CHAR, N_COLS INT); CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN (ID); CREATE INDEX FOR_IND ON SYS_FOREIGN (FOR_NAME); CREATE INDEX REF_IND ON SYS_FOREIGN (REF_NAME); CREATE TABLE SYS_FOREIGN_COLS(ID CHAR, POS INT, FOR_COL_NAME CHAR, REF_COL_NAME CHAR); CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS); {code} It is a bad idea to identify the tables and columns by names, because it forces InnoDB to update these tables when tables or columns are renamed. Furthermore, the names are stored and sorted as if they were encoded in {{latin1_swedish_ci}}, while they should really have been handled as {{utf8_unicode_ci}} ({{system_charset_info}}). The {{SYS_FOREIGN.ID}} consists of the schema name and a user-specified constraint name. If no constraint name is specified by the user, then it will be generated like {{childtablename_ibfk_1}}, {{childtablename_ibfk_2}}, and so on. The {{ID}} must be unique within the database. In main memory, InnoDB stores the foreign key metadata in a data structure {{dict_foreign_t}}. This structure stores both table names and table pointers. Tables that are attached to foreign key constraints cannot be evicted from the InnoDB table cache. The reason for this is that whenever a table that is attached to a foreign key constraint is modified, we may have to read or modify records in other tables. As part of this task, the {{FOREIGN KEY}} metadata would be stored in the SQL layer. A natural place could be the {{.frm}} file. Alas, if we only stored the information in the {{.frm}} file of one of the tables that are part of the constraint, then we would have to read all {{.frm}} files before any table can be modified, because we must be aware of all tables that the current table {{REFERENCES}} to or that are pointing to the current table by {{REFERENCES}} clauses. If we stored the {{FOREIGN KEY}} metadata in the {{.frm}} files of both the child and the parent tables, then {{RENAME TABLE}} would have to update a large number of {{.frm}} files in an atomic and crash-safe fashion. This would require transactional logging, which is currently missing. h2. Proposal: Store {{FOREIGN KEY}} Constraints in {{.frk}} Files It would seem simplest to introduce a new type of files for storing {{FOREIGN KEY}} constraints. All these files would be read at startup, and all {{.frm}} files pointed to by them would be opened. If there is a mismatch (say, one or both of the tables does not exist, or column names or types do not match, or the columns are not covered by appropriate indexes), a warning would be issued to the server error log, and the constraint would be ignored. Columns that are part of the constraint could be identified either by name or by position in the {{SHOW CREATE TABLE}} output. Position could be preferred, because the {{.frk}} files would not have to be updated when renaming columns. But, then they would have to be updated when dropping, adding or reordering columns. Updates of the {{.frk}} files must not only be crash-safe, but transactional and atomic together with updates of {{.frm}} files and the storage engine data. This will require some form of logging that is synchronized with InnoDB transaction commit, also when it happens inside {{ha_innobase::commit_inplace_alter_table()}}. h3. Option: {{constraintname.frk}} (one {{REFERENCES}} clause per file) Each {{constraintname.frk}} file would have to contain both the child and parent table names, and identify the participating columns. We would potentially have a very large number of files, and many of them would have to be atomically and transactionally updated in {{RENAME TABLE}}. h3. Option: {{childtablename.frk}} (multiple {{REFERENCES}} clauses per file) The child table name would be implied by the file name; only the parent table names would be stored in the file, along with the identities of the columns. The uniqueness of constraint identifiers would be enforced in memory only. (We have to keep all foreign key constraints in memory anyway.) {{RENAME TABLE}} of a child table would only have to transactionally rename {{childtablename.frk}} and {{childtablename.frm}}. Renaming a parent table will have to transactionally rewrite the {{childtablename.frk}} to update the {{REFERENCES}} clauses. With {{childtablename.frk}} files (and assuming that the InnoDB internal data dictionary will some day be removed in MDEV-11655), users could manually rename child tables by renaming files, but renaming parent tables would still require editing the {{.frk}} file. We might consider using an editing-friendly file format. In that case, the transactional logging and crash recovery for {{.frk}} file operations must be made as robust as possible. |
Currently, only the InnoDB storage engine is storing information about {{FOREIGN KEY}} constraints. The metadata is stored in two hidden tables that are only accessible to InnoDB. The tables are created in the InnoDB internal SQL parser as follows:
{code:sql} CREATE TABLE SYS_FOREIGN(ID CHAR, FOR_NAME CHAR, REF_NAME CHAR, N_COLS INT); CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN (ID); CREATE INDEX FOR_IND ON SYS_FOREIGN (FOR_NAME); CREATE INDEX REF_IND ON SYS_FOREIGN (REF_NAME); CREATE TABLE SYS_FOREIGN_COLS(ID CHAR, POS INT, FOR_COL_NAME CHAR, REF_COL_NAME CHAR); CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS); {code} It is a bad idea to identify the tables and columns by names, because it forces InnoDB to update these tables when tables or columns are renamed. Furthermore, the names are stored and sorted as if they were encoded in {{latin1_swedish_ci}}, while they should really have been handled as {{utf8_unicode_ci}} ({{system_charset_info}}). The {{SYS_FOREIGN.ID}} consists of the schema name and a user-specified constraint name. If no constraint name is specified by the user, then it will be generated like {{childtablename_ibfk_1}}, {{childtablename_ibfk_2}}, and so on. The {{ID}} must be unique within the database. In main memory, InnoDB stores the foreign key metadata in a data structure {{dict_foreign_t}}. This structure stores both table names and table pointers. Tables that are attached to foreign key constraints cannot be evicted from the InnoDB table cache. The reason for this is that whenever a table that is attached to a foreign key constraint is modified, we may have to read or modify records in other tables. As part of this task, the {{FOREIGN KEY}} metadata would be stored in the SQL layer. A natural place could be the {{.frm}} file. Alas, if we only stored the information in the {{.frm}} file of one of the tables that are part of the constraint, then we would have to read all {{.frm}} files before any table can be modified, because we must be aware of all tables that the current table {{REFERENCES}} to or that are pointing to the current table by {{REFERENCES}} clauses. If we stored the {{FOREIGN KEY}} metadata in the {{.frm}} files of both the child and the parent tables, then {{RENAME TABLE}} would have to update a large number of {{.frm}} files in an atomic and crash-safe fashion. This would require transactional logging, which is currently missing. h2. Proposal: Store {{FOREIGN KEY}} Constraints in {{.frk}} Files It would seem simplest to introduce a new type of files for storing {{FOREIGN KEY}} constraints. All these files would be read at startup, and all {{.frm}} files pointed to by them would be opened. If there is a mismatch (say, one or both of the tables does not exist, or column names or types do not match, or the columns are not covered by appropriate indexes), a warning would be issued to the server error log, and the constraint would be ignored. Columns that are part of the constraint could be identified either by name or by position in the {{SHOW CREATE TABLE}} output. Position could be preferred, because the {{.frk}} files would not have to be updated when renaming columns. But, then they would have to be updated when dropping, adding or reordering columns. Updates of the {{.frk}} files must not only be crash-safe, but transactional and atomic together with updates of {{.frm}} files and the storage engine data. This will require some form of logging that is synchronized with InnoDB transaction commit, also when it happens inside {{ha_innobase::commit_inplace_alter_table()}}. h3. Option: {{constraintname.frk}} (one {{REFERENCES}} clause per file) Each {{constraintname.frk}} file would have to contain both the child and parent table names, and identify the participating columns. We would potentially have a very large number of files, and many of them would have to be atomically and transactionally updated in {{RENAME TABLE}}. h3. Option: {{childtablename.frk}} (multiple {{REFERENCES}} clauses per file) The child table name would be implied by the file name; only the parent table names would be stored in the file, along with the identities of the columns. The uniqueness of constraint identifiers would be enforced in memory only. (We have to keep all foreign key constraints in memory anyway.) {{RENAME TABLE}} of a child table would only have to transactionally rename {{childtablename.frk}} and {{childtablename.frm}}. Renaming a parent table will have to transactionally rewrite the {{childtablename.frk}} to update the {{REFERENCES}} clauses. With {{childtablename.frk}} files (and assuming that the InnoDB internal data dictionary will some day be removed in MDEV-11655), users could manually rename child tables by renaming files, but renaming parent tables would still require editing the {{.frk}} file. We might consider using an editing-friendly file format. In that case, the transactional logging and crash recovery for {{.frk}} file operations must be made as robust as possible. |
Rank | Ranked higher |
Epic Link | PT-77 [ 68558 ] | PT-92 [ 69417 ] |
Link | This issue relates to MDEV-17123 [ MDEV-17123 ] |
Link |
This issue is blocked by |
Component/s | Server [ 13907 ] | |
NRE Projects | RM_long_term | RM_long_term RM_105_CANDIDATE |
Link | This issue relates to MDEV-12483 [ MDEV-12483 ] |
Link | This issue relates to MDEV-10393 [ MDEV-10393 ] |
Labels | foreign-keys |
Link |
This issue blocks |
Reporter | Sergei Golubchik [ serg ] | Marko Mäkelä [ marko ] |
Fix Version/s | 10.5 [ 23123 ] |
Assignee | Aleksey Midenkov [ midenok ] |
Priority | Major [ 3 ] | Critical [ 2 ] |
Link |
This issue is blocked by |
Link |
This issue relates to |
Link |
This issue is blocked by |
Status | Open [ 1 ] | In Progress [ 3 ] |
Link | This issue blocks MDEV-12483 [ MDEV-12483 ] |
Link | This issue relates to MDEV-12483 [ MDEV-12483 ] |
Status | In Progress [ 3 ] | Stalled [ 10000 ] |
Fix Version/s | 10.6 [ 24028 ] |
Fix Version/s | 10.5 [ 23123 ] |
Priority | Critical [ 2 ] | Major [ 3 ] |
Link | This issue relates to MDEV-21964 [ MDEV-21964 ] |
Link | This issue blocks MDEV-22361 [ MDEV-22361 ] |
Status | Stalled [ 10000 ] | In Progress [ 3 ] |
Priority | Major [ 3 ] | Critical [ 2 ] |
Link |
This issue blocks |
Link |
This issue blocks |
Link |
This issue blocks |
Link |
This issue relates to |
Link |
This issue blocks |
Link |
This issue relates to |
Link | This issue relates to MDEV-19453 [ MDEV-19453 ] |
Rank | Ranked higher |
Rank | Ranked higher |
Link |
This issue relates to |
Link |
This issue is blocked by |
Link |
This issue is blocked by |
Assignee | Aleksey Midenkov [ midenok ] | Sergei Golubchik [ serg ] |
Status | In Progress [ 3 ] | In Review [ 10002 ] |
Link | This issue is part of MDEV-12483 [ MDEV-12483 ] |
Link | This issue blocks MDEV-12483 [ MDEV-12483 ] |
Link |
This issue is blocked by |
Link |
This issue is blocked by |
Link |
This issue relates to |
Fix Version/s | 10.7 [ 24805 ] | |
Fix Version/s | 10.6 [ 24028 ] |
Link |
This issue relates to |
Link | This issue relates to MDEV-25935 [ MDEV-25935 ] |
Priority | Critical [ 2 ] | Major [ 3 ] |
Fix Version/s | 10.8 [ 26121 ] | |
Fix Version/s | 10.7 [ 24805 ] |
Link | This issue relates to MDEV-27180 [ MDEV-27180 ] |
Link | This issue relates to MDEV-27180 [ MDEV-27180 ] |
Link | This issue is blocked by MDEV-27180 [ MDEV-27180 ] |
Workflow | MariaDB v3 [ 87719 ] | MariaDB v4 [ 131767 ] |
Fix Version/s | 10.9 [ 26905 ] | |
Fix Version/s | 10.8 [ 26121 ] |
Link | This issue relates to MDEV-25885 [ MDEV-25885 ] |
Fix Version/s | 10.10 [ 27530 ] | |
Fix Version/s | 10.9 [ 26905 ] |
Fix Version/s | 10.11 [ 27614 ] | |
Fix Version/s | 10.10 [ 27530 ] |
Fix Version/s | 10.12 [ 28320 ] | |
Fix Version/s | 10.11 [ 27614 ] |
Description |
Currently, only the InnoDB storage engine is storing information about {{FOREIGN KEY}} constraints. The metadata is stored in two hidden tables that are only accessible to InnoDB. The tables are created in the InnoDB internal SQL parser as follows:
{code:sql} CREATE TABLE SYS_FOREIGN(ID CHAR, FOR_NAME CHAR, REF_NAME CHAR, N_COLS INT); CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN (ID); CREATE INDEX FOR_IND ON SYS_FOREIGN (FOR_NAME); CREATE INDEX REF_IND ON SYS_FOREIGN (REF_NAME); CREATE TABLE SYS_FOREIGN_COLS(ID CHAR, POS INT, FOR_COL_NAME CHAR, REF_COL_NAME CHAR); CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS); {code} It is a bad idea to identify the tables and columns by names, because it forces InnoDB to update these tables when tables or columns are renamed. Furthermore, the names are stored and sorted as if they were encoded in {{latin1_swedish_ci}}, while they should really have been handled as {{utf8_unicode_ci}} ({{system_charset_info}}). The {{SYS_FOREIGN.ID}} consists of the schema name and a user-specified constraint name. If no constraint name is specified by the user, then it will be generated like {{childtablename_ibfk_1}}, {{childtablename_ibfk_2}}, and so on. The {{ID}} must be unique within the database. In main memory, InnoDB stores the foreign key metadata in a data structure {{dict_foreign_t}}. This structure stores both table names and table pointers. Tables that are attached to foreign key constraints cannot be evicted from the InnoDB table cache. The reason for this is that whenever a table that is attached to a foreign key constraint is modified, we may have to read or modify records in other tables. As part of this task, the {{FOREIGN KEY}} metadata would be stored in the SQL layer. A natural place could be the {{.frm}} file. Alas, if we only stored the information in the {{.frm}} file of one of the tables that are part of the constraint, then we would have to read all {{.frm}} files before any table can be modified, because we must be aware of all tables that the current table {{REFERENCES}} to or that are pointing to the current table by {{REFERENCES}} clauses. If we stored the {{FOREIGN KEY}} metadata in the {{.frm}} files of both the child and the parent tables, then {{RENAME TABLE}} would have to update a large number of {{.frm}} files in an atomic and crash-safe fashion. This would require transactional logging, which is currently missing. h2. Proposal: Store {{FOREIGN KEY}} Constraints in {{.frk}} Files It would seem simplest to introduce a new type of files for storing {{FOREIGN KEY}} constraints. All these files would be read at startup, and all {{.frm}} files pointed to by them would be opened. If there is a mismatch (say, one or both of the tables does not exist, or column names or types do not match, or the columns are not covered by appropriate indexes), a warning would be issued to the server error log, and the constraint would be ignored. Columns that are part of the constraint could be identified either by name or by position in the {{SHOW CREATE TABLE}} output. Position could be preferred, because the {{.frk}} files would not have to be updated when renaming columns. But, then they would have to be updated when dropping, adding or reordering columns. Updates of the {{.frk}} files must not only be crash-safe, but transactional and atomic together with updates of {{.frm}} files and the storage engine data. This will require some form of logging that is synchronized with InnoDB transaction commit, also when it happens inside {{ha_innobase::commit_inplace_alter_table()}}. h3. Option: {{constraintname.frk}} (one {{REFERENCES}} clause per file) Each {{constraintname.frk}} file would have to contain both the child and parent table names, and identify the participating columns. We would potentially have a very large number of files, and many of them would have to be atomically and transactionally updated in {{RENAME TABLE}}. h3. Option: {{childtablename.frk}} (multiple {{REFERENCES}} clauses per file) The child table name would be implied by the file name; only the parent table names would be stored in the file, along with the identities of the columns. The uniqueness of constraint identifiers would be enforced in memory only. (We have to keep all foreign key constraints in memory anyway.) {{RENAME TABLE}} of a child table would only have to transactionally rename {{childtablename.frk}} and {{childtablename.frm}}. Renaming a parent table will have to transactionally rewrite the {{childtablename.frk}} to update the {{REFERENCES}} clauses. With {{childtablename.frk}} files (and assuming that the InnoDB internal data dictionary will some day be removed in MDEV-11655), users could manually rename child tables by renaming files, but renaming parent tables would still require editing the {{.frk}} file. We might consider using an editing-friendly file format. In that case, the transactional logging and crash recovery for {{.frk}} file operations must be made as robust as possible. |
Currently, only the InnoDB storage engine is storing information about {{FOREIGN KEY}} constraints. The metadata is stored in two hidden tables that are only accessible to InnoDB. The tables are created in the InnoDB internal SQL parser as follows: {code:sql} CREATE TABLE SYS_FOREIGN(ID CHAR, FOR_NAME CHAR, REF_NAME CHAR, N_COLS INT); CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN (ID); CREATE INDEX FOR_IND ON SYS_FOREIGN (FOR_NAME); CREATE INDEX REF_IND ON SYS_FOREIGN (REF_NAME); CREATE TABLE SYS_FOREIGN_COLS(ID CHAR, POS INT, FOR_COL_NAME CHAR, REF_COL_NAME CHAR); CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS); {code} It is a bad idea to identify the tables and columns by names, because it forces InnoDB to update these tables when tables or columns are renamed. Furthermore, the names are stored and sorted as if they were encoded in {{latin1_swedish_ci}}, while they should really have been handled as {{utf8_unicode_ci}} ({{system_charset_info}}). The {{SYS_FOREIGN.ID}} consists of the schema name and a user\-specified constraint name. If no constraint name is specified by the user, then it will be generated like {{childtablename_ibfk_1}}, {{childtablename_ibfk_2}}, and so on. The {{ID}} must be unique within the database. In main memory, InnoDB stores the foreign key metadata in a data structure {{dict_foreign_t}}. This structure stores both table names and table pointers. Tables that are attached to foreign key constraints cannot be evicted from the InnoDB table cache. The reason for this is that whenever a table that is attached to a foreign key constraint is modified, we may have to read or modify records in other tables. As part of this task, the {{FOREIGN KEY}} metadata would be stored in the SQL layer. A natural place could be the {{.frm}} file. Alas, if we only stored the information in the {{.frm}} file of one of the tables that are part of the constraint, then we would have to read all {{.frm}} files before any table can be modified, because we must be aware of all tables that the current table {{REFERENCES}} to or that are pointing to the current table by {{REFERENCES}} clauses. If we stored the {{FOREIGN KEY}} metadata in the {{.frm}} files of both the child and the parent tables, then {{RENAME TABLE}} would have to update a large number of {{.frm}} files in an atomic and crash\-safe fashion. This would require transactional logging, which is currently missing. h2. Proposal: Store {{FOREIGN KEY}} Constraints in {{.frk}} Files It would seem simplest to introduce a new type of files for storing {{FOREIGN KEY}} constraints. All these files would be read at startup, and all {{.frm}} files pointed to by them would be opened. If there is a mismatch (say, one or both of the tables does not exist, or column names or types do not match, or the columns are not covered by appropriate indexes), a warning would be issued to the server error log, and the constraint would be ignored. Columns that are part of the constraint could be identified either by name or by position in the {{SHOW CREATE TABLE}} output. Position could be preferred, because the {{.frk}} files would not have to be updated when renaming columns. But, then they would have to be updated when dropping, adding or reordering columns. Updates of the {{.frk}} files must not only be crash\-safe, but transactional and atomic together with updates of {{.frm}} files and the storage engine data. This will require some form of logging that is synchronized with InnoDB transaction commit, also when it happens inside {{ha_innobase::commit_inplace_alter_table()}}. h3. Option: {{constraintname.frk}} (one {{REFERENCES}} clause per file) Each {{constraintname.frk}} file would have to contain both the child and parent table names, and identify the participating columns. We would potentially have a very large number of files, and many of them would have to be atomically and transactionally updated in {{RENAME TABLE}}. h3. Option: {{childtablename.frk}} (multiple {{REFERENCES}} clauses per file) The child table name would be implied by the file name; only the parent table names would be stored in the file, along with the identities of the columns. The uniqueness of constraint identifiers would be enforced in memory only. (We have to keep all foreign key constraints in memory anyway.) {{RENAME TABLE}} of a child table would only have to transactionally rename {{childtablename.frk}} and {{childtablename.frm}}. Renaming a parent table will have to transactionally rewrite the {{childtablename.frk}} to update the {{REFERENCES}} clauses. With {{childtablename.frk}} files (and assuming that the InnoDB internal data dictionary will some day be removed in MDEV-11655), users could manually rename child tables by renaming files, but renaming parent tables would still require editing the {{.frk}} file. We might consider using an editing-friendly file format. In that case, the transactional logging and crash recovery for {{.frk}} file operations must be made as robust as possible. |
Fix Version/s | 11.2 [ 28603 ] | |
Fix Version/s | 11.0 [ 28320 ] |
Link | This issue relates to MDEV-30416 [ MDEV-30416 ] |
Link |
This issue relates to |
Link |
This issue blocks |
Fix Version/s | 11.4 [ 29301 ] | |
Fix Version/s | 11.2 [ 28603 ] |
Priority | Major [ 3 ] | Critical [ 2 ] |
Link | This issue blocks MDEV-12094 [ MDEV-12094 ] |
Fix Version/s | 11.5 [ 29506 ] | |
Fix Version/s | 11.4 [ 29301 ] |
Issue Type | Task [ 3 ] | New Feature [ 2 ] |
Fix Version/s | 11.6 [ 29515 ] | |
Fix Version/s | 11.5 [ 29506 ] |
Fix Version/s | 11.7 [ 29815 ] | |
Fix Version/s | 11.6 [ 29515 ] |
Fix Version/s | 11.8 [ 29921 ] | |
Fix Version/s | 11.7 [ 29815 ] |
Link | This issue blocks MDEV-12483 [ MDEV-12483 ] |
Link |
This issue relates to |
Link | This issue includes MDEV-20865 [ MDEV-20865 ] |
Fix Version/s | 11.9 [ 29945 ] | |
Fix Version/s | 11.8 [ 29921 ] |
Fix Version/s | 12.1 [ 29992 ] | |
Fix Version/s | 12.0 [ 29945 ] |
Fix Version/s | 12.3 [ 30147 ] | |
Fix Version/s | 12.1 [ 29992 ] |