连接到子查询的选择查询将永远运行

时间:2017-08-17 08:55:51

标签: mysql

对于我的mysql-audit-tables project,我想将原始数据表的定义与相关的审计表进行比较,后者具有相同的列和一些标题信息。

编辑:为此问题创建sqlfiddle后,我发现它在sqlfiddle(MYSQL V5.6)上正常工作,而在我在windows上的5.7安装中我得到了不同的结果对于3个查询中的第三个(删除列)。

编辑:添加了要与之比较的示例表:

CREATE TABLE `audit_testdata`.`testtable` (-- the data table!
  `text_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `text_type_id` bigint(20) unsigned NOT NULL,
  `text_other_id` bigint(20) unsigned NOT NULL,
  `text_lng_id` bigint(20) unsigned NOT NULL,
  `text_access_id` bigint(20) DEFAULT NULL,
  `text_html` text,
  `text_plain` text,
  `testadd` varchar(42) DEFAULT NULL,-- new field to test queries!
  PRIMARY KEY (`text_id`),
  UNIQUE KEY `text_id` (`text_id`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8;

CREATE TABLE `audit`.`testtable_audit` ( -- audit table, simplified
  `audit_seq` bigint(20) unsigned NOT NULL,
  `audit_pk` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `audit_timestamp` timestamp NOT NULL,
  `text_id` bigint(20) unsigned NOT NULL COMMENT 'pk_testtable: ',-- change d field to test queries.
  `text_type_id` bigint(20) unsigned NOT NULL,
  `text_other_id` bigint(20) unsigned NOT NULL,
  `text_lng_id` bigint(20) unsigned NOT NULL,
  `text_access_id` bigint(20) DEFAULT NULL,
  `text_html` text,
  `text_plain` text,
  `text_symbol` blob,-- deleted field to test queries.
  PRIMARY KEY (`audit_pk`),
  UNIQUE KEY `audit_pk` (`audit_pk`),
  KEY `text_id` (`text_id`),
  KEY `audit_timestamp` (`audit_timestamp`),
  KEY `audit_seq` (`audit_seq`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

一些准备意见:

DROP VIEW IF EXISTS v_audit_info_tables;
CREATE VIEW v_audit_info_tables AS 
SELECT CONCAT('`',TABLE_SCHEMA,'`.`',TABLE_NAME,'`') AS FQ_TABLE_NAME,
       TABLE_SCHEMA,TABLE_NAME
FROM information_schema.TABLES;

DROP VIEW IF EXISTS v_audit_info_columns;
CREATE VIEW v_audit_info_columns AS 
SELECT CONCAT('`',TABLE_SCHEMA,'`.`',TABLE_NAME,'`') AS FQ_TABLE_NAME,
       CONCAT('`',TABLE_SCHEMA,'`.`',TABLE_NAME,'`.`',COLUMN_NAME,'`') AS FQ_COLUMN_NAME,
       TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME,COLUMN_TYPE,IS_NULLABLE,COLUMN_KEY,COLUMN_DEFAULT,
       CONCAT('`',COLUMN_NAME,'` ',
        UPPER(COLUMN_TYPE),
        IF(IS_NULLABLE='YES',' NULL ',' NOT NULL '),
        'COMMENT ''',REPLACE(COLUMN_COMMENT,'''',''''''),'''') AS FQ_COLUMN_CHANGE
FROM information_schema.COLUMNS;

这是一个映射视图,用于链接每个数据表及其审计表。在我的真实项目中,有一些配置表可供使用:

DROP VIEW IF EXISTS v_audit_map_tables;
CREATE VIEW v_audit_map_tables AS 
SELECT dat.FQ_TABLE_NAME AS dat_fq_table_name,dat.TABLE_SCHEMA AS dat_table_schema,dat.TABLE_NAME AS dat_table_name,
aud.FQ_TABLE_NAME AS aud_fq_table_name,aud.TABLE_SCHEMA AS aud_table_schema,aud.TABLE_NAME as aud_table_name
FROM v_audit_info_tables dat JOIN v_audit_info_tables  aud
ON aud.TABLE_NAME = CONCAT(dat.TABLE_NAME,'_audit') 
WHERE dat.TABLE_SCHEMA = 'audit_testdata' AND aud.TABLE_SCHEMA = 'audit';
;

这里有一个完整的图片,用于修改列的工作查询:

SELECT dat.FQ_COLUMN_NAME,dat.FQ_COLUMN_CHANGE,AUD.FQ_COLUMN_CHANGE,
    CONCAT('ALTER TABLE ',aud.FQ_TABLE_NAME,' MODIFY COLUMN `',dat.COLUMN_NAME,'` ',dat.FQ_COLUMN_CHANGE) AS modify_cmd,
    dat.FQ_TABLE_NAME,aud.FQ_TABLE_NAME
FROM v_audit_info_columns dat JOIN v_audit_info_columns aud 
ON dat.COLUMN_NAME = aud.COLUMN_NAME
WHERE dat.FQ_COLUMN_CHANGE <> aud.FQ_COLUMN_CHANGE
;

这是非工作查询,它​​似乎永远存在:

SELECT dat.FQ_COLUMN_NAME,dat.FQ_COLUMN_CHANGE,NULL,
    CONCAT('ALTER TABLE ',audmap.aud_fq_table_name,' ADD COLUMN `',dat.COLUMN_NAME,'` ',dat.FQ_COLUMN_CHANGE) AS modify_cmd,
    dat.FQ_TABLE_NAME,audmap.aud_fq_table_name
FROM v_audit_info_columns dat JOIN v_audit_map_tables audmap
ON audmap.dat_fq_table_name = dat.FQ_TABLE_NAME
WHERE dat.COLUMN_NAME NOT IN 
    (SELECT DISTINCT aud.COLUMN_NAME FROM v_audit_info_columns aud 
        WHERE aud.TABLE_NAME = audmap.aud_table_name AND aud.TABLE_SCHEMA = audmap.aud_table_schema
        -- AND aud.FQ_TABLE_NAME = audmap.aud_fq_table_name
    );

我先尝试aud.FQ_TABLE_NAME = audmap.aud_fq_table_name,然后直接点击TABLE_NAME/TABLE_SCHEMA。我已经查看了其他一些问题,所以我的新想法是重新设计最终查询,但我仍然不知道如何。

EDIT-2:现在这是一个缓慢的工作解决方案,上面的查询很慢而且错误。让它运作的基本提示是MYSQL documentation。我将这些案例放在一个UNION中,它在我的窗口上运行大约6秒钟,所以我仍然有兴趣优化更多:

SELECT dat.FQ_COLUMN_NAME,dat.FQ_COLUMN_CHANGE AS dat_change,AUD.FQ_COLUMN_CHANGE AS aud_change,
    CONCAT('ALTER TABLE ',aud.FQ_TABLE_NAME,' MODIFY COLUMN `',dat.COLUMN_NAME,'` ',dat.FQ_COLUMN_CHANGE) AS modify_cmd,
    dat.FQ_TABLE_NAME AS dat_table_name,aud.FQ_TABLE_NAME AS aud_table_name
FROM v_audit_info_columns dat JOIN v_audit_info_columns aud 
ON dat.COLUMN_NAME = aud.COLUMN_NAME
JOIN v_audit_map_tables audmap 
ON dat.FQ_TABLE_NAME = audmap.dat_fq_table_name AND aud.FQ_TABLE_NAME = audmap.aud_fq_table_name
WHERE dat.FQ_COLUMN_CHANGE <> aud.FQ_COLUMN_CHANGE
UNION
SELECT dat.FQ_COLUMN_NAME,dat.FQ_COLUMN_CHANGE,NULL,
    CONCAT('ALTER TABLE ',audmap.aud_fq_table_name,' ADD COLUMN `',dat.COLUMN_NAME,'` ',dat.FQ_COLUMN_CHANGE) AS modify_cmd,
    dat.FQ_TABLE_NAME,audmap.aud_fq_table_name
FROM v_audit_info_columns dat 
JOIN v_audit_map_tables audmap ON (audmap.dat_fq_table_name = dat.FQ_TABLE_NAME)
WHERE NOT EXISTS (SELECT 1 FROM v_audit_info_columns aud WHERE dat.aud_fq_column_name = aud.FQ_COLUMN_NAME)
UNION
SELECT aud.FQ_COLUMN_NAME,NULL,aud.FQ_COLUMN_CHANGE,
    CONCAT('-- ALTER TABLE ',aud.FQ_TABLE_NAME,' DROP COLUMN `',aud.COLUMN_NAME,'`') AS modify_cmd,
    audmap.dat_fq_table_name, audmap.aud_fq_table_name
 FROM v_audit_info_columns aud JOIN v_audit_map_tables audmap
ON audmap.aud_fq_table_name = aud.FQ_TABLE_NAME
WHERE NOT EXISTS (SELECT 1 FROM v_audit_info_columns dat 
    WHERE dat.fq_column_name = CONCAT(audmap.dat_fq_table_name,'.`',aud.COLUMN_NAME,'`'))
;

1 个答案:

答案 0 :(得分:0)

为了优化联合,还需要两个带索引的表,从我的计算机上的6.14秒到0.063秒。他们是:

CREATE TABLE IF NOT EXISTS audit12_columns (
        FQ_TABLE_NAME VARCHAR(133), 
        FQ_COLUMN_NAME VARCHAR(200) PRIMARY KEY,
        TABLE_SCHEMA VARCHAR(64),
        TABLE_NAME VARCHAR(64), 
        COLUMN_NAME VARCHAR(64), 
        FQ_COLUMN_CHANGE VARCHAR(2000), 
        aud_fq_column_name VARCHAR(200),
        INDEX (FQ_TABLE_NAME),
        UNIQUE KEY (TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME),
        UNIQUE KEY (aud_fq_column_name)
        );

CREATE TABLE IF NOT EXISTS audit12_mapping (
        dat_fq_table_name VARCHAR(200) PRIMARY KEY, 
        dat_table_schema VARCHAR(64), 
        dat_table_name VARCHAR(64), 
        aud_fq_table_name VARCHAR(200) UNIQUE, 
        aud_table_schema VARCHAR(64), 
        aud_table_name VARCHAR(64),
        UNIQUE KEY (dat_table_schema,dat_table_name),
        UNIQUE KEY (aud_table_schema,aud_table_name) 
        );

表可以由相应的视图填充,并且在逐个表的基础上完成,只能将这些数据条目提供给表:

DELETE FROM audit12_mapping;
    INSERT INTO audit12_mapping (dat_fq_table_name, dat_table_schema, dat_table_name, 
        aud_fq_table_name, aud_table_schema, aud_table_name)
    SELECT dat_fq_table_name, dat_table_schema, dat_table_name, 
        aud_fq_table_name, aud_table_schema, aud_table_name
        FROM v_audit_map_tables 
        WHERE dat_fq_table_name = i_id_data_table;-- limit to actual entry.

DELETE FROM audit12_columns;
    INSERT INTO audit12_columns (FQ_TABLE_NAME, FQ_COLUMN_NAME, 
        TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, 
        FQ_COLUMN_CHANGE, aud_fq_column_name)
    SELECT FQ_TABLE_NAME, FQ_COLUMN_NAME, 
        TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, 
        FQ_COLUMN_CHANGE, aud_fq_column_name
        FROM v_audit_info_columns
        WHERE (FQ_TABLE_NAME = i_id_data_table OR FQ_TABLE_NAME = l_id_audit_table);

最终的UNION查询如下所示:

SELECT CONCAT('ALTER TABLE ',aud.FQ_TABLE_NAME,' MODIFY COLUMN ',dat.FQ_COLUMN_CHANGE,';') AS modify_cmd
        FROM audit12_columns dat JOIN audit12_columns aud 
        ON dat.COLUMN_NAME = aud.COLUMN_NAME
        JOIN audit12_mapping audmap 
        ON dat.FQ_TABLE_NAME = audmap.dat_fq_table_name AND aud.FQ_TABLE_NAME = audmap.aud_fq_table_name
        WHERE dat.FQ_COLUMN_CHANGE <> aud.FQ_COLUMN_CHANGE
    UNION
    SELECT CONCAT('ALTER TABLE ',audmap.aud_fq_table_name,' ADD COLUMN ',dat.FQ_COLUMN_CHANGE,';') AS modify_cmd
        FROM audit12_columns dat 
        JOIN audit12_mapping audmap ON (audmap.dat_fq_table_name = dat.FQ_TABLE_NAME)
        WHERE NOT EXISTS (SELECT 1 FROM audit12_columns aud WHERE dat.aud_fq_column_name = aud.FQ_COLUMN_NAME)
    UNION
    SELECT CONCAT('-- ALTER TABLE ',aud.FQ_TABLE_NAME,' DROP COLUMN `',aud.COLUMN_NAME,'`;') AS modify_cmd
        FROM audit12_columns aud JOIN audit12_mapping audmap
        ON audmap.aud_fq_table_name = aud.FQ_TABLE_NAME
        WHERE NOT EXISTS (SELECT 1 FROM audit12_columns dat 
            WHERE dat.fq_column_name = CONCAT(audmap.dat_fq_table_name,'.`',aud.COLUMN_NAME,'`'))
    ;

顺便说一句,我首先尝试将audit12_columns和audit12_mapping作为临时表,但是我遇到了ERROR 1137:无法重新打开表:&#39; temp_table&#39;错误,已在mysql documentation中解释。