select into outfile問題一則
01 背景
select into outfile無論對於開發或DBA來說,都是一個愛不釋手的匯出資料的方式。相比mysqldump,它能夠對需要匯出的欄位做限制,很好的滿足了某些不需要匯出主鍵欄位的場景或分庫分表的環境下資料的重新匯入。且與load data infile配合起來,無疑是一款資料匯入匯出的利器。最近,開發小夥伴在測試環境使用select into file進行資料匯出時,碰到了一個問題,覺得很有必要跟大家分享一下。
02 問題概述
客戶某系統(以下簡稱ebank)開發小夥伴報告說自己的一個指令碼使用了select into outfile對資料進行匯出。然而資料無法匯出。以下是該問題的排查過程。
03 排查過程及思路
1.檢視資料庫使用者是否具有file許可權
首先透過show grants命令檢視ebank使用者是否具有匯出資料的file許可權,如下程式碼所示:
mysql> show grants for ebank@"%"; +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Grants for ebank@% | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | GRANT USAGE ON *.* TO 'ebank'@'%' | | GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `test`.* TO 'ebank'@'%' | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 2 rows in set (0.00 sec)
由於該使用者不具有file許可權,因此第一步首先為該使用者賦予file許可權,由於file許可權屬於全域性許可權,因此為ebank使用者賦予file許可權時不必指明該許可權專門賦予哪一個schema,若指明schema,則會報錯。
mysql> grant file on test.* to "ebank"@"%"; ERROR 1221 (HY000): Incorrect usage of DB GRANT and GLOBAL PRIVILEGES
若在賦予file許可權時不對schema作限制,則可以賦權成功。
mysql> grant file on *.* to "ebank"@"%"; Query OK, 0 rows affected (0.00 sec)
2.檢視資料庫的全域性引數secure_file_priv
使用者許可權已經賦予,接下來要看資料庫的全域性引數secure_file_priv是否開啟。
mysql> show variables like "secure_file_priv"; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | secure_file_priv | null | +------------------+-------+ 1 row in set (0.01 sec)
secure_file_priv的取值有三種,其一為一個具體的路徑,那麼使用select into outfile匯出資料時,則只能匯出在secure_file_priv指定的路徑下;其二為一個空字串,在此種取值下,那麼資料庫不會對匯出的路徑做限制,只要select into outfile指定匯出的路徑對於作業系統層面的mysql使用者具有讀寫執行的許可權,則資料即可正常匯出;其三取值為null,此種取值代表資料庫不能使用select into outfile匯出資料。
由於此時資料庫secure_file_priv的取值為null,是不能匯出資料的,因此需要在配置檔案中重新指定secure_file_priv的取值,由於資料庫的資料目錄為/data2,因此將/data2設定select into outfile的匯出路徑。
mysql> show variables like "secure_file_priv"; +------------------+---------+ | Variable_name | Value | +------------------+---------+ | secure_file_priv | /data2/ | +------------------+---------+ 1 row in set (0.01 sec)
測試一下是否能夠正常匯出資料。
[root@multi-master2 tmp]# mysql -uebank -pebank -h127.0.0.1 mysql> use test Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> select * from player into outfile "/data2/player.txt"; Query OK, 4 rows affected (0.00 sec) mysql> ^DBye [root@multi-master2 tmp]# cat /data2/player.txt 2 messi sf agen 4 neymar wf brazil 6 ramos CB spain 8 xavi AMF spain
資料匯出成功。
3.開發的特殊需求
測試完select into outfile匯出資料成功後,對於DBA的工作已然完成。將資料庫調整的結果告訴開發後,但開發仍然認為不符合需求。由於開發在此測試環境的伺服器上也有一個作業系統使用者ebank,因此開發需要將資料匯出的目錄設定為/home/ebank/data。遵從開發的需求,將secure_file_priv的取值改為/home/ebank/data,並將/home/ebank/data目錄的屬主改為mysql。
[root@multi-master2 ebank]# chown -R mysql:mysql data/ [root@multi-master2 ebank]# ll total 4 drwxr-xr-x. 2 mysql mysql 4096 Aug 21 03:54 data [root@multi-master2 ebank]# [root@multi-master2 ebank]# pwd /home/ebank
由於已經有了之前的測試,而這次的修改在本人看來,和前一次只有路徑上的差別,因此,在配置檔案中修改secure_file_priv的取值為/home/ebank/data後,重啟資料庫,並未手工進行select into outfile匯出的測試,就通知開發可以進行資料的匯出了。然而問題還是出現了,開發仍然反饋無法成功匯出資料。
收到此反饋後,便手動進行了一次資料匯出測試。
[root@multi-master2 data]# mysql -uebank -pebank -h127.0.0.1 mysql> use test Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> select * from player into outfile "/home/ebank/data/player.txt"; ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
奇怪的是這次的確無法匯出資料,看到這個報錯,首先確認是否是資料庫的配置出了問題。
mysql> show variables like "secure_file_priv"; +------------------+-------------------+ | Variable_name | Value | +------------------+-------------------+ | secure_file_priv | /home/ebank/data/ | +------------------+-------------------+ 1 row in set (0.00 sec) mysql> show grants for "ebank"@"%"; +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Grants for ebank@% | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | GRANT FILE ON *.* TO 'ebank'@'%' | | GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `test`.* TO 'ebank'@'%' | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 2 rows in set (0.00 sec)
資料庫的配置沒有問題,且之前設定的/home/mysql/data目錄的屬主也為mysql,此時對於這個問題的研究陷入了瓶頸。
百思不得其解之際,請教了大佬,經過大佬的指點,方知此問題的關鍵點如下圖所示:
[root@multi-master2 data]# cd /home/ [root@multi-master2 home]# ll total 8 drwx------. 5 ebank ebank 4096 Aug 21 03:54 ebank drwx------. 7 mysql mysql 4096 Aug 20 14:34 mysql
ebank使用者家目錄在建立之初的訪問許可權為700,資料庫匯出資料的存放路徑為/home/ebank/data,雖然data目錄的屬主為mysql,但由於上層路徑ebank目錄的屬主為700,即除ebank使用者外的所有使用者都對此目錄無執行許可權,因此使用select into outfile匯出資料時會報錯。
根據此原因可以透過以下方法解決該問題:
-
將/home/ebank的訪問許可權改為701,即任何使用者對/home/ebank目錄都有執行許可權。
[root@multi-master2 home]# ll total 8 drwx------. 5 ebank ebank 4096 Aug 21 03:54 ebank drwx------. 7 mysql mysql 4096 Aug 20 14:34 mysql [root@multi-master2 home]# chmod 701 ebank/ [root@multi-master2 home]# ll total 8 drwx-----x. 5 ebank ebank 4096 Aug 21 03:54 ebank drwx------. 7 mysql mysql 4096 Aug 20 14:34 mysql [root@multi-master2 home]# mysql -uebank -pebank -h127.0.0.1 mysql> use test Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> select * from player into outfile "/home/ebank/data/player1.txt"; Query OK, 4 rows affected (0.01 sec) mysql> ^DBye [root@multi-master2 home]# cat /home/ebank/data/player1.txt 2 messi sf agen 4 neymar wf brazil 6 ramos CB spain 8 xavi AMF spain [root@multi-master2 home]#
透過上述配置,資料匯出成功。
04 select into outfile的替代方案
-
select into outfile可以方便的把表中的資料匯出為csv檔案,且可以根據需求篩選需要的欄位。但有時需要匯出多張表,且對錶的欄位沒有篩選需求時,對每一張表一條條的去寫匯出的SQL語句未免顯得麻煩。這時候就可以使用mysqldump來對資料進行匯出。
-
使用mysqldump將資料匯出成csv格式時,需要加一個引數--tab,該引數指定檔案匯出的路徑。對於每一張表,會生成兩個檔案,一個txt檔案,以csv格式儲存了表中的資料,一個sql檔案,儲存了表結構。
#如下語句為匯出test庫下的所有表 [root@multi-master2 data]# mysqldump --single-transaction -uebank -pebank -h127.0.01 --tab="/home/ebank/data" test mysqldump: [Warning] Using a password on the command line interface can be insecure. Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don't want to restore GTIDs, pass --set-gtid-purged=OFF. To make a complete dump, pass --all-databases --triggers --routines --events. SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN; SET @@SESSION.SQL_LOG_BIN= 0; -- -- GTID state at the beginning of the backup -- SET @@GLOBAL.GTID_PURGED='8d52b2f3-c316-11e9-8b39-000c29a27f67:1-40'; SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN; [root@multi-master2 data]# ll total 16 -rw-r--r--. 1 root root 1623 Aug 21 06:51 player.sql -rw-rw-rw-. 1 mysql mysql 69 Aug 21 06:51 player.txt -rw-r--r--. 1 root root 1426 Aug 21 06:51 team.sql -rw-rw-rw-. 1 mysql mysql 61 Aug 21 06:51 team.txt
05 小結
綜上所述,無論是要使用select into outfile匯出資料,還是要使用mysqldump --tab的方式匯出資料,都需要具有以下許可權:
1、訪問資料庫的使用者需要擁有匯出資料所需的file許可權。
2、資料庫引數secure_file_priv不能為null,要麼取值為空,即不對匯出的路徑做限制,要麼為具體指定的路徑。
3、資料匯出的路徑對於作業系統的mysql使用者必須是可寫的,且其上層目錄對於mysql使用者來說必須是可執行的。
| 作者簡介
許升輝·沃趣科技資料庫工程師
熟悉MySQL體系結構和innodb儲存引擎工作原理;擅長資料庫問題分析,效能調優;對mysql備份恢復、資料遷移有豐富的實踐。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28218939/viewspace-2659599/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 使用SELECT…INTO OUTFILE匯出文字檔案
- 記一次 MySQL select for update 死鎖問題MySql
- mysql insert into ... select的鎖問題MySql
- ORACLE SELECT INTO NO_DATA_FOUND問題Oracle
- laravel-admin select聯動問題Laravel
- 正則問題整理
- 【Oracle】Oracle wrong result一則(優化器問題)Oracle優化
- MySQL中SELECT+UPDATE併發更新問題MySql
- Java處理正則匹配卡死(正則回溯問題)Java
- Ant Design Select元件下拉選項隨頁面滾動與Select框分離問題元件
- 由select for update鎖等待問題引發的深入思考
- JavaScript 中正則匹配時結果不一致的問題JavaScript
- 記錄一則AIX使用裸裝置安裝OracleRAC的問題AIOracle
- 簡單分析MySQL 一則慢日誌監控誤報問題MySql
- mysql 高併發 select update 併發更新問題解決方案MySql
- 完美解決html中select的option不能隱藏的問題。HTML
- 關於jquery控制select下拉框自動展開問題jQuery
- 業務規則的常見問題解答
- Laravel 自定義驗證規則的問題Laravel
- 關於 mysql 中的 select * from table_a,table_b 的問題MySql
- 解決問題的三條規則 | Yonatan Zunger
- 解決select2 在modal中搜尋框無效的問題
- 規則引擎面臨的問題和挑戰 - brcommunityUnity
- 一個小問題
- 思考一個問題
- SQL最佳化 | MySQL問題處理案例分享三則MySql
- 【譯】原則問題:直面設計中的核心實質
- Vue3中無法為el-tree-select設定反選問題分析Vue
- 請問一個 authorize的問題
- select 下拉框用 Select select = new Select (element) 方法失敗
- 請教一個 sqlchemy 問題,在 pycharm 下 select 方法為什麼不提示支援的 where 等關鍵詞呢SQLPyCharm
- 揹包問題的一道經典問題
- node express 在使用mysql執行SELECT count(*) from xx獲取總數取值格式問題ExpressMySql
- 關於轉義符 在php正則中的匹配問題PHP
- Webpack devServer.proxy反向代理地址模糊相似規則問題WebdevServer
- 發現一個問題
- 一個問題諮詢
- Hbase問題小結(一)