1. 程式人生 > 資料庫 >Mysql複製表三種實現方法及grant解析

Mysql複製表三種實現方法及grant解析

如何快速的複製一張表

首先建立一張表db1.t,並且插入1000行資料,同時建立一個相同結構的表db2.t

假設,現在需要把db1.t裡面的a>900的資料行匯出來,插入到db2.t中

mysqldump方法

幾個關鍵引數註釋:

  • –single-transaction的作用是,在匯出資料的時候不需要對錶db1.t加表鎖,而是使用
  • START TRANSACTION WITH CONSISTENT SNAPSHOT的方法;
  • –no-create-info的意思是,不需要匯出表結構;
  • –result-file指定了輸出檔案的路徑,其中client表示生成的檔案是在客戶端機器上的。

匯出csv檔案

select * from db1.t where a>900 into outfile '/server_tmp/t.csv';

這條語句會將結果儲存在服務端。如果你執行命令的客戶端和MySQL服務端不在同一個機器上,客戶端機器的臨時目錄下是不會生成t.csv檔案的。

這條命令不會幫你覆蓋檔案,因此你需要確保/server_tmp/t.csv這個檔案不存在,否則執行語句時就會因為有同名檔案的存在而報錯。

得到.csv匯出檔案後,你就可以用下面的load data命令將資料匯入到目標表db2.t中。

load data infile '/server_tmp/t.csv' into table db2.t;

開啟檔案/server_tmp/t.csv,以製表符(\t)作為欄位間的分隔符,以換行符(\n)作為記錄之間的分隔符,進行資料讀取;

啟動事務。

判斷每一行的欄位數與表db2.t是否相同:

  • 若不相同,則直接報錯,事務回滾;
  • 若相同,則構造成一行,呼叫InnoDB引擎介面,寫入到表中。

重複步驟3,直到/server_tmp/t.csv整個檔案讀入完成,提交事務。

物理拷貝方法

mysqldump方法和匯出CSV檔案的方法,都是邏輯導資料的方法,也就是將資料從表db1.t中讀出來,生成文字,然後再寫入目標表db2.t中。有物理導資料的方法嗎?比如,直接把db1.t表的.frm檔案和.ibd檔案拷貝到db2目錄下,是否可行呢?答案是不行的。

因為,一個InnoDB表,除了包含這兩個物理檔案外,還需要在資料字典中註冊。直接拷貝這兩個檔案的話,因為資料字典中沒有db2.t這個表,系統是不會識別和接受它們的。

在MySQL 5.6版本引入了可傳輸表空間(transportable tablespace)的方法,可以通過匯出+匯入表空間的方式,實現物理拷貝表的功能。

假設現在的目標是在db1的庫下,複製一個跟表t相同的表r,具體執行步驟:

  • 執行create table r like t,建立一個相同表結構的空表,
  • 執行alter table r discard tablespace,這時候r.ibd檔案會被刪除
  • 執行flush table t for export這時候會生成一個t.cfg
  • 在db1目錄下執行cp t.cfg r.cfg; cp t.ibd r.ibd;這兩個命令;
  • 執行unlock tables,這時候t.cfg檔案會被刪除;
  • 執行alter table r import tablespace,將這個r.ibd檔案作為表r的新的表空間,由於這個檔案的資料內容和t.ibd是相同的,所以表r中就有了和表t相同的資料。

這三種方法的優缺點

物理拷貝的方式速度最快,尤其對於大表拷貝來說是最快的方法。但必須是全拷貝,不能是部分拷貝,需要到伺服器上拷貝資料,在使用者無法登入資料庫主機時無法使用,而且源表和目標表都必須是innodb引擎。

用mysqldump生成包含INSERT語句檔案的方法,可以在where引數增加過濾條件,來實現只匯出部分資料。這個方式的不足之一是,不能使用join這種比較複雜的where條件寫法。

用select … into outfile的方法是最靈活的,支援所有的SQL寫法。但,這個方法的缺點之一就是,每次只能匯出一張表的資料,而且表結構也需要另外的語句單獨備份。

後兩種都是邏輯備份方式,可以跨引擎使用的。

mysql全域性許可權

SELECT * FROM MYSQL.USER WHERE USER='UA'\G 顯示所有許可權

作用域整個mysql,資訊儲存在mysql的user表裡

賦予使用者ua一個最高許可權:

grant all privileges on *.* to 'ua'@'%' with grant option;

這個grant命令做了兩個動作:分別將磁碟中的mysql.user表裡將許可權的欄位都修改為Y,和記憶體中的acl_user中使用者對應的物件將access值修改為‘全1'

如果有新的客戶端使用使用者名稱ua登入成功,mysql會為新連線維護一個執行緒物件,所有關於全域性許可權的判斷,都是直接使用執行緒物件內部儲存的許可權位。

grant命令對於全域性許可權,同時更新了磁碟和相應的記憶體,接下來新建立的連線會使用新的許可權
對於已經存在的連線,它的全域性許可權不受grant的影響。
如果要回收上面許可權:

revoke all privileges on *.* from 'ua'@'%';

同樣也是相對應的兩個操作,磁碟中許可權欄位修改位N,記憶體中物件的access的值修改位0。

mysqlDB許可權

grant all privileges on db1.* to 'ua'@'%' with grant option;

使用SELECT * FROM MYSQL.DB WHERE USER = 'UA'\G來檢視當前使用者的db許可權,同樣的也是對磁碟和記憶體中的物件修改許可權。

db許可權儲存在mysql.db表中

注意:和全域性許可權不同,db許可權會對已經存在的連線物件產生影響。

mysql表許可權和列許可權

表許可權放在mysql.tables_priv中,列許可權存放在mysql.columns_priv中,這兩類許可權組合起來存放在記憶體的hash結構column_priv_hash中。

跟db許可權類似,這兩個許可權每次grant的時候都會修改資料表,也會同步修改記憶體中的hash結構,因此,這兩類許可權的操作,也會影響到已經存在的連線。

flush privileges的使用場景

有些文件裡提到,grant之後馬上執行flush privileges命令,才能使賦權語句生效。其實更準確的說法應該是在資料表中的許可權跟記憶體中的許可權資料不一致的時候,flush privileges語句可以用來重建記憶體資料,達到一致狀態。

比如某時刻刪除了資料表的記錄,但是記憶體的資料還存在,導致了給使用者賦權失敗,因為在資料表中找不到記錄。
同時重新建立這個使用者也不行,因為在記憶體判斷的時候,會認為這個使用者還存在。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。