2017-08-17 109 views
0

對於我的mysql-audit-tables project我想比較原始數據表的定義和相關的審計表,它具有相同的列和一些標題信息。連接到子查詢的選擇查詢永遠運行

編輯:針對此問題創造一個sqlfiddle後,我發現在sqlfiddle(MYSQL V5.6)它是工作,在我的5.7安裝在Windows上我有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和直接ADRESS的TABLE_NAME/TABLE_SCHEMA。我看了很多其他問題,所以我的新想法是重新設計最終查詢,但我仍然不知道,如何。

EDIT-2:現在這裏是緩慢的工作解決方案,上面的查詢是緩慢的和錯誤的。讓它工作的重要提示是在MYSQL documentation。我把案件集中在一個UNION,這在我的Windows運行約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,'`')) 
; 
+0

我已經添加了'WHERE TABLE_SCHEMA IN('audit','audit_testdata');'對於前三個視圖,它將最終查詢增強到了2.5秒。此外,我使用新的'FQ_COLUMN_NAME'在子查詢中進行搜索,如果將子查詢限制爲指定的表,則2.5中還會有0.016。我仍然對更好的解決方案感興趣,因爲我的測試環境2.5沒問題,但是對於多個表,我預計執行時間會更長...... – Myonara

回答

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臨時表,但我碰到的錯誤1137:無法重新打開表格:'temp_table'錯誤,這在mysql documentation中有解釋。