Oracle系列之--Profile
Oracle系列之–Profile
最近一個項目數據庫換了19c,然后就開始頻繁報錯,并且是個很詭異的錯:java.sql.SQLException: ORA-01012: not logged on,定眼一看很簡單,仔細一想不對勁。所有單詞都認識,連起來就不懂了,這個錯一般是我們使用PL/SQL這種開發工具時會出現的錯誤,一般和人為操作有關;但是這是程序報的錯,程序也沒有更改過,數據庫也很正常,然而就是頻繁的出現這個錯誤信息。
借由這個錯誤,今天就來說說Oracle中的資源限制,你也可以理解為環境變量。在Oracle中針對每一個用戶也都是有響應的資源限制參數,平常使用我們是無感的,因為在沒有顯式設置時Oracle會為每一個用戶使用一個默認的環境變量,即Default_Profile。所以我們并不需要單獨進行設置,最近那個項目報錯并不是換了19c才報的錯,是換了DBA所以才報的錯,表面掩蓋了實質。。。新DBA對項目使用的Oracle用戶修改了一個參數限制idle_time=15,默認情況下是UNLIMITED的,也就是無限制,被DBA改成了15,因此才導致了出現ORA-01012的錯誤,這個參數限制了空閑15分鐘的數據庫連接會被后臺進程PMON強制釋放回收。
問題已經找到,接下來就說說Profile吧。(以下內容都是從官網直接獲取,邊翻譯邊理解的,如有理解偏差請多指教。)
一、Profile概念
Oracle中的權限管理其實是非常精細的,只是在平常使用中我們都為了圖省事兒全都使用了dba用戶,這種最大化權限的操作方式讓我們對數據庫的訪問變得簡單,同時也留下了安全隱患以及一些性能問題。而Profile作為安全策略的一部分,可以為用戶使用的各種Oracle系統級別的資源進行限制,通過這種方式能夠定制化的限制用戶的對數據庫各種資源的異常消耗和占用,比如說cpu時間、IO、數據塊訪問量、會話數、超時時間等。
在大型系統中,這種有針對性的限制是非常有用的,因為數據庫資源總量是一定的,如果某一用戶消耗過多資源可能會對其他用戶產生不利影響,但是設置資源限制會對用戶創建會話有一些性能影響,用戶在連接數據庫的時候數據庫需要把所有資源限制數據做導入。
二、限制級別和類型
對資源的限制有session級別和call級別,能夠限制cpu時間、邏輯讀以及其他一些類型。這里先介紹一下各種概念,具體的操作在后邊會進行羅列。
1、session級別
這個就是比較熟知會話級別的限制,限制當前會話對數據庫cpu及內存資源的訪問,如果一旦超出限制數據庫就會中斷當前會話并對事務進行回滾,同時返回錯誤信息說明已經達到session級別的限制。該事務中之前執行的操作都還是完整的,對當前操作只能執行commit、rollback或者disconnect(執行disconnect時默認當前事務會提交),除此之外當前會話不能再執行任何其他操作,執行就會報錯。
2、call級別
call級別比session級別更加精細,能夠控制執行某一sql時的資源限制,call即調用。用戶去執行一條sql能有什么操作呢,其實每一條sql的執行都會分幾步來進行,如sql美化、預編譯、編譯、執行計劃、加鎖、內存檢索、數據塊檢索等,因此在執行sql的不同階段都會產生多個調用,就是為了防止在多個調用時出現資源消耗過大的現象而對call級別進行資源限制。如果達到了call級別的限制那么數據庫就會終止處理當前sql,并對當前sql進行回滾,然后返回一個錯誤信息。對當前事務中其他sql是沒有影響的,連接也不會斷開。這種控制更精準但是操作起來也會更復雜。
3、CPU時間限制
每條sql執行時都會占用cpu time,為了防止一個大量數據操作的sql或異常sql占用過多的cpu time資源,可以對session級別和call級別的cpu時間進行動態或靜態限制,單位時百分之一秒。
4、邏輯讀限制
涉及到邏輯讀就說明內存已經無法命中,必須要進行I/O操作,這對于數據庫來說是十分昂貴的。內存命中率低于95%時就說明數據庫出現了性能問題,這是數據庫系統的主要性能瓶頸。為了防止某個事務占用過多I/O資源,可以在session級別和call級別對邏輯讀的數據塊數目做出限制。邏輯讀包括從內存和磁盤讀取數據塊。這些限制是通過調用或會話期間執行的塊讀取次數來設置和度量的。
5、其他資源限制
對于其他資源的限制一般都是session級別的,可以限制:
-
用戶的并發會話數:同一時間該用戶能夠有多少會話數,這在開發環境中是不應該設置的。
-
會話空閑超時時間:對于空閑連接,如果兩次call之間的時間間隔達到設置值會話連接就會被強制回收,當前事務回滾,釋放資源。在當前會話中再次執行sql操作就會報錯,返回實例已經斷開連接的的錯誤信息(文章最開始的錯誤就是這個設置引起的),單位是分鐘。
**需要指出的是:**就算當前會話因為該參數被釋放,計算用戶和會話資源限制時還是會被計算在內(比如用戶的并發數限制)
-
會話連接超時時間:會話的最大連接時間,無論會話是否空閑,當達到這個限制后,這個會話都會被回滾,資源釋放,單位是分鐘。該參數配置時就需要謹慎,如果配置不當可能會導致業務的中斷。
**需要指出的是:**出于性能考慮oracle并不會連續的實時監控空閑時間和連接時間,所以數據庫在檢測到會話超時的時間和配置的時間之間會有幾分鐘的差值,如果配置15分鐘的空閑超時時間,實際的空閑超時時間可能在15-17分鐘左右
-
會話占用的SGA空間:能夠限制SGA使用空間大小,單位是K或M。
三、限制資源設置建議
上面說到對于資源的限制可以使用靜態的數值和動態限制,這其實是一種取舍。靜態的數值設置簡單,效果顯而易見,但是適用的場景也比較固定,一旦偶有超出限制的資源操作就會出現錯誤;而動態的限制就比較靈活,設置起來也會比較復雜,動態的設置是通過分配各資源的使用限制權重和一個總的資源消耗閾值進行控制的。這種動態控制的前提是需要對系統比較熟悉,能夠收集或者已經了解關于系統每種資源使用類型的歷史信息。
對于靜態參數需要配合resource_limit參數使用才能生效,通過v$parameter進行查看是否開啟,使用alter system set resource_limit=true scope=both;來修改該參數狀態;而動態參數的設置需要通過dba_profiles表中的composite_limit參數來控制開啟,否則只設置各資源限制參數的權重是不生效的,使用alter profile <profile_name> limit composite_limit <integer_num/unlimited/default>;后邊會具體說每項參數的具體設置方法和設置值。
四、Profile的作用
對profile有所了解后就明白它的作用,就是用作資源管理。就像開頭所說的,profile就像是環境變量,每個數據庫用戶都必須要有一套且只能有一套對應的profile,多個用戶可以公用同一套profile;未進行明確聲明的用戶用的就是數據庫默認的profile–DEFAULT_PROFILE。
作為資源管理的一種方式,其實使用profile進行管理的資源還是非常有限的,oracle官方推薦使用Database Resource Manager管理系統資源,這是一種更加精細,更加專業的資源管理方式;允許oracle控制硬件級別的資源分配來更好的發揮數據庫的性能。不過在實際應用中使用profile方式的更多,相對于Database Resource Manager更加復雜的管理配置方式,profile就顯得簡單了許多,并且profile所能限制的這幾種資源對于大多數企業用戶來說已經基本夠用了。
對于profile的另外一種用途就是對數據庫密碼資源的控制,這在數據庫日常管理中相對來說更常用到。上面說到,想要啟用資源限制就需要使用alter system set resource_limit=true scope=both;來開啟該功能,針對的就是資源管理,而profile中的密碼管理始終是開啟的,不需要也不能進行手動關閉。
參考官網:Configuring User Resource Limits
五、使用Profile
上面說了那么多基本都是概念性質,接下來就具體說說這個profile是如何使用的,包括創建、刪除、修改其中的參數等。
1、創建
首先,想要創建profile必須要有create profile權限,這個和create user權限是一樣的;創建之后只是有了一個profile,想要使用還必須要指定一個用戶,才能發揮應有的作用;其次,還需要數據庫開啟resource_limit功能,前面已經說過了,就不再贅述了;最后,profile有兩部分組成,resource部分和password部分。通過dba_profiles中RESOURCE_TYPE字段可以清晰的看到兩部分區別:
| DEFAULT | COMPOSITE_LIMIT | KERNEL | UNLIMITED |
| DEFAULT | SESSIONS_PER_USER | KERNEL | UNLIMITED |
| DEFAULT | CPU_PER_SESSION | KERNEL | UNLIMITED |
| DEFAULT | CPU_PER_CALL | KERNEL | UNLIMITED |
| DEFAULT | LOGICAL_READS_PER_SESSION | KERNEL | UNLIMITED |
| DEFAULT | LOGICAL_READS_PER_CALL | KERNEL | UNLIMITED |
| DEFAULT | IDLE_TIME | KERNEL | UNLIMITED |
| DEFAULT | CONNECT_TIME | KERNEL | UNLIMITED |
| DEFAULT | PRIVATE_SGA | KERNEL | UNLIMITED |
| DEFAULT | FAILED_LOGIN_ATTEMPTS | PASSWORD | 10 |
| DEFAULT | PASSWORD_LIFE_TIME | PASSWORD | UNLIMITED |
| DEFAULT | PASSWORD_REUSE_TIME | PASSWORD | UNLIMITED |
| DEFAULT | PASSWORD_REUSE_MAX | PASSWORD | UNLIMITED |
| DEFAULT | PASSWORD_VERIFY_FUNCTION | PASSWORD | NULL |
| DEFAULT | PASSWORD_LOCK_TIME | PASSWORD | 1 |
| DEFAULT | PASSWORD_GRACE_TIME | PASSWORD | 7 |
因此,在創建profile時就是要指定以上這些參數的值,如果不指定,那么就會使用默認值,即default的值。
截取官網上的兩個圖來說明創建profile的具體sql語句:
這個是創建語句,其中橢圓中的profile是你的profile名稱,如dev_profile/prod_profile等,起一個標識作用;LIMIT后邊的參數分為兩部分,resource_parameters和password_parameters,這里只是更便于說明,雖然這么標識但是實際SQL中并不會有明顯區分,在LIMIT后邊直接羅列的就是上面表格中的那些參數名,這里應該是通過PASSWORD前綴去區分是否是密碼參數的。
對于resource_parameters部分:
包含兩部分,參數名和參數值。參數名就是上邊表格列出的9個,對于參數值,前8個有整型、無限制和默認三種選擇;對于SGA的限制則有一點區別就是有單位區別,像K、M、G、T等,前8個單位都是固定的。
對于password_parameters部分:
也包含兩部分,參數名和參數值。參數值的不同區別在于使用表達式或者函數,當然這里使用使用整型數值也還是可以的。
具體每個參數的含義及其單位會在后邊單獨一一講解。需要單獨說一下對于profile的名稱需要符合Oracle的命名規范,包括不建議使用“SYS”和“ORA”開頭的名稱,名稱中不建議使用雙引號,如果使用“(雙引號)要成對出現,同時會自動忽略名稱中的雙引號,不區分大小寫,名稱的長度限制雖然最長可以達到128字節,但是建議名稱不超過30字節等等。具體的命名規則可以參照官方:Database Object Names and Qualifiers
這里再給出兩個具體的實例以作說明:
/**創建resource相關資源限制profile**/ CREATE PROFILE app_user LIMIT SESSIONS_PER_USER UNLIMITED CPU_PER_SESSION UNLIMITED CPU_PER_CALL 3000 CONNECT_TIME 45 LOGICAL_READS_PER_SESSION DEFAULT LOGICAL_READS_PER_CALL 1000 PRIVATE_SGA 15KCOMPOSITE_LIMIT 5000000;創建了一個名為“app_user”的profile,并進行了如下限制:
- 對當前用戶下會話的并發數不做限制;
- 執行sql時占用的cpu時間不做限制;
- 執行單條sql占用的cpu時間限制不超過30秒;
- 每個連接最長使用時間未45分鐘;
- 每個會話中能夠進行的邏輯數據塊讀使用默認值;
- 每次調用sql能夠讀取內存和磁盤中的數據塊不超過1000個;
- 每個會話不能占用超過15KB的SGA空間;
- 每個會話的總資源消耗成本不能超過500萬;
- 沒有對連接空閑時間和密碼進行限制,oracle將會使用默認profile進行限制。
創建了一個“app_user2”的profile并進行了密碼相關限制。對于密碼驗證功能使用了一個verify_function函數,具體如何使用驗證函數或者想要自定義驗證函數可以參考:Introducing Oracle Database Security
2、刪除
刪除時也需要有drop權限,并配合cascade關鍵字進行刪除,其實與刪除表的操作一樣。DROP PROFILE <profile_name> CASCADE;
刪除profile后,該profile所指定的用戶將會自動被分配給Default Profile;因此,Default Profile是無法被刪除的,就是上邊表格中的這些參數是不能被刪除的。同時,刪除的profile不會應用到當前已連接的會話中,在之后創建的會話中才會生效。
參考官網:CREATE PROFILE
六、限制資源參數
在創建profile的sql語句中可以看到,在參數的值中兩個較常見的值:UNLIMITED和DEFAULT。
UNLIMITED
表示對資源使用沒有上限,可以盡可能大的占用系統資源;在密碼設置中表示對該參數無限制。
DEFAULT
表示使用默認的profile配置,對于一些不必要或可以忽略的參數可以使用默認值,在默認profile中大部分參數值是unlimited的,因此大部分的default其實等于unlimited。
如果在指定資源參數時不顯式的指定參數的值,那么該參數會自動使用default。
RESOURCE_PARAMETERS
SESSIONS_PER_USER
限制單個用戶的并發會話數
CPU_PER_SESSION
指定單個會話的cpu使用時間限制,單位百分之一秒
CPU_PER_CALL
指定每次調用時的cpu使用時間限制,這里的調用指解析、執行和讀取等方法,單位百分之一秒
CONNECT_TIME
指定一個會話的總運行時間限制,單位分鐘
IDLE_TIME
指定一個會話中允許連續的非活動時間,如果一直在執行sql或其他數據庫交互操作的時間不計算在內,對比connect_time可以清楚這里是指空閑連接超時時間,單位分鐘
LOGICAL_READS_PER_SESSION
指定一個會話中允許讀取的數據塊數量,包括從內存(邏輯讀)和磁盤讀取(物理讀)的數據塊,單位個
LOGICAL_READS_PER_CALL
在每次調用sql時允許讀取的數據塊數量,單位個
PRIVATE_SGA
指定會話可以在SGA共享池中分配的私有空間數量,該參數生效的前提是數據庫啟用了SGA管理內存模式,即是在ASMM模式才生效。對于該參數的單位有bytes、K、M、G、T、P、E,從小到大都是1024倍的關系,如果不指定單位數據庫默認使用字節作為單位,建議明確單位限制,在某些情況下不指定單位可能會有錯誤信息出現。
COMPOSITE_LIMIT
限制單個會話能夠使用的系統總資源成本,單位是一種服務單位。計算方式是CPU_PER_SESSION, CONNECT_TIME, LOGICAL_READS_PER_SESSION和PRIVATE_SGA的加權和。具體的使用和計算方式會在后邊單獨講解。
PASSWORD_PARAMETERS
設置密碼參數時,FAILED_LOGIN_ATTEMPTS和PASSWORD_REUSE_MAX這兩個參數值是整型數字,除了這兩個參數之外的其他參數,單位都是天。但是之前說了這些參數都可以是表達式,是因為在某些場景下可能天這個單位過大(比如測試時),因此可以用表達式來縮短參數設置的時間,比如使用1/1440限定為1分鐘,1/86400限定為1秒鐘等,當然這里并不是說不能使用十進制來表示分鐘和秒,只是使用表達式更為清晰,如果你使用0.0417來表示一個小時也是完全可以的,但是顯然這個數字不方便計算并且這也不是一個精確值,只是1/24的近似值。不過這個值也有上下限,最小值為1秒,最大值為24855天。
FAILED_LOGIN_ATTEMPTS
指定連續登錄失敗的次數限制,超過此次數當前用戶將會被鎖定。如果不指定當前參數默認值為10次。
PASSWORD_LIFE_TIME
限制使用相同密碼進行身份驗證的天數,超過這個天數沒有進行密碼更改將會使密碼過期,導致無法登錄。如果不指定當前參數默認是180天。對于這個參數可能會有人有些疑問,自己創建的數據庫用戶一直都沒有更改過密碼也沒有提示過密碼過期的情況,這是因為你在創建用戶時沒有指定密碼有效期,在create user中使用PASSWORD EXPIRE子句將會使該參數的設置值生效。
另外對于設置該參數時需要特別注意,此處設置的時間并不是從當前設置時間開始生效的,是從最近一次修改當前用戶的密碼開始計算的,用戶的創建時間和密碼修改時間記錄在sys.user$表中,CTIME表示創建時間,PTIME表示修改時間。假如你設置了1天有效期,那么oracle將會從PTIME中記錄的時間開始計算,超過1天沒有修改密碼將會使當前用戶的密碼有效期設置超時,無法再次登錄。這一點是需要特別注意的。
想要查詢已經創建的用戶是否設置了密碼有效期,可以使用如下sql:
SELECT CREATED, EXPIRY_DATE FROM DBA_USERS WHERE USERNAME = '<user_name>';對于密碼有效期的設置對當前已經登錄的用戶是不生效的,數據庫會從下一次用戶連接時開始計算時間。因此,作為DBA想要修改該參數時需要確保所配置的profile指定的用戶都沒有進行連接,可以通過v$session視圖進行查看。否則可能出現特權用戶,即已經連接的用戶一直不斷開連接,那么這個設置對那個連接永遠不會生效。
PASSWORD_REUSE_TIME and PASSWORD_REUSE_MAX
這兩個參數是結合使用的。password_reuse_time指定密碼可重用的周期,如設置為10則表示10天內修改的密碼不能和上次相同;password_reuse_max指定密碼不能重復使用的次數間隔,如設置3則表示最近一次修改的密碼不能和最近三次中任意一次修改的密碼相同。
如果你將其中一個設置為unlimited,那么密碼將永遠不能重復,同樣如果指定為default數據庫的默認配置也是unlimited,這是一樣的效果。但是如果你將兩個參數都設置為unlimited那么數據庫就會忽略這兩個參數。
PASSWORD_LOCK_TIME
連續登陸失敗達到限制次數后密碼鎖定的天數,默認值是1天。
PASSWORD_GRACE_TIME
密碼過期的寬限期,配合password_life_time使用,能夠使密碼在使用超過有效期后并不會馬上禁止登錄,會在登錄時進行警告ORA-28002: The password will expire within n days;當超過寬限期還未進行密碼修改則密碼將會徹底失效。如果不設置該參數默認寬限期是7天。
PASSWORD_VERIFY_FUNCTION
密碼復雜度校驗函數允許在創建profile時將函數腳本作為參數進行傳遞,oracle有默認的驗證腳本,你也可以自定義驗證腳本。
對于自定義腳本的函數,只需要將該參數的值設置為自定義的函數名即可,不過自定義的校驗函數必須在SYS用戶下,并且當前用戶(創建profile的用戶)必須有可執行權限。
如果該參數設置為null則表示不啟用密碼復雜度校驗。
對于默認的密碼驗證函數11g和12c有所不同,11g使用的兩個默認函數是VERIFY_FUNCTION和VERIFY_FUNCTION_11G,在12c中進行了廢棄,使用了校驗強度更強的ORA12C_VERIFY_FUNCTION和ORA12C_STRONG_VERIFY_FUNCTION來代替。想要查看這兩個函數或者自定義函數可以查看${ORACLE_HOEM}/rdbms/admin/utlpwdmg.sql腳本,在11g中該腳本中定義了VERIFY_FUNCTION,想要看12c中的ORA12C_VERIFY_FUNCTION則需要查看${ORACLE_HOEM}/rdbms/admin/catpvf.sql腳本(11g中是沒有這個腳本的,函數直接定義在utlpwdmg中,12c中將兩者分離了)
參考官網:Semantics、Specifying a Profile for the User
七、修改靜態配置
對于已經創建的profile想要添加、修改、刪除配置參數均是通過alter profile語句進行的。修改后的參數只會對后續再新創建的會話產生影響,而不會影響當前會話,所以修改配置后請不要使用當前會話驗證。
想要使用修改語句首先必須擁有alter權限,其次對于12c及以后版本由于使用容器管理實現可插拔,因此在修改配置時需要指定特定的容器,如果想要對所有容器均生效那就需要在根容器中進行操作。
這里又借了官網一個圖來展示具體的sql:
與創建profile語句基本類似,這里多了一個CONTAINER子句來標定修改的配置作用域是當前容器還是全部容器,在12c之前是沒有該參數的,就需要寫了。其他兩個子句resource_parameters和password_parameters的參數配置則和創建時的一樣。
舉個栗子:
ALTER PROFILE app_user LIMITFAILED_LOGIN_ATTEMPTS 5PASSWORD_LOCK_TIME 1PASSWORD_LIFE_TIME 90PASSWORD_GRACE_TIME 5SESSIONS_PER_USER 5IDLE_TIME 2;這個sql設置適用于app_user限定的數據庫用戶,登陸失敗嘗試次數為5次,失敗5次后賬戶鎖定1天。密碼有效期為90天,寬限期5天,也就是說超過90天不修改密碼會在你下次登陸時給出警告提示,超過95天不修改密碼當前用戶密碼將失效導致無法使用當前用戶登錄數據庫。用戶的會話并發數最大為5個,空閑連接超時時間為2分鐘。你要知道alter語句既是修改,也是添加,也是刪除的含義。當前設置如果app_user配置中沒有定義過這兩個參數,那么就等于新增;如果之前定義過這些參數,那么就是將參數修改為當前數值;如果不是具體數值而使用default則代表刪除之前定義的值而使用default配置的值進行限定。
另外,要使以上配置生效別忘了執行另一條sql:ALTER SYSTEM SET resource_limit=TRUE SCOPE=BOTH;
參考官網:ALTER PROFILE
八、修改動態配置
之前說到,靜態參數修改相對來說比較簡單明顯,對于參數中的數字只要知道單位就能明顯知道限定的范圍,如:5次、90天、2分鐘等。但是有時候這些固定參數太過生硬太過暴力,對于服務器來說可能達不到最大的優化性能,這個時候使用動態參數就能讓數據庫自己決定每個參數的限定范圍從而達到更高效的利用服務器性能的目的,而我們需要做的就是配置每項參數的權重然后再限定一下資源消耗總閾值就行了。
這就是說我們設定一個資源消耗的計算公式,oracle根據我們設定的公式來動態分配每種資源的限制范圍,最終結果是在資源消耗超過我們設定的總閾值時中止會話并返回錯誤信息。設置的前提當然也是需要有alter權限。對于總閾值的設定是在profile中使用COMPOSITE_LIMIT配置來限定,sql語句如:alter profile app_user limit COMPOSITE_LIMIT 5000000;即設置app_user限定的用戶使用數據庫總資源閾值不能超過500萬個服務單位。
下面具體說說資源權重的配置,目前能夠配置的資源有四種:CPU_PER_SESSION、LOGICAL_READS_PER_SESSION、CONNECT_TIME、PRIVATE_SGA。通過RESOURCE_COST表能夠進行查詢每種資源的權重配額,看著資源名稱是不是很熟悉?這確實和靜態配置很相似,兩者可以共同限定會話對數據庫資源的訪問限制。
再來看個sql圖:
sql幾乎是非常固定的,每種參數的值都是整數類型。設置后對當前會話和之后新創建的會話均生效。oracle會將你設置的每項配置和其權重相乘,然后相加得出最后的總消耗成本,與前面設置的COMPOSITE_LIMIT配置進行比較,如果超過設定的閾值就會中斷當前會話并返回錯誤信息。
對于每項配置的含義其實已經不需要多說,前面已經介紹過。這里說一下配置對應的值和之前的不一樣,這里配置的值是所指配置的權重,而不是限定閾值。比如這里設置CUP_PER_SESSION為50并不是會話占用cpu的時間,而是計算總成本時計算會話占用cpu時間的計算權重為50,其他的自行理解。
你分配給每個資源的權重決定了該資源的使用對總資源成本的貢獻,換句話說你分配的權重越大代表的就是你越重視該項資源的消耗程度,即該項資源可能存在性能短板,因此不能過多消耗。如果您沒有為資源分配權重,那么權重默認為0,隨后對資源的使用不會增加成本。
參考官網:ALTER RESOURCE COST
總結
以上是生活随笔為你收集整理的Oracle系列之--Profile的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大数据与个人隐私的平衡:懂你,但不认识你
- 下一篇: excel日期改成字符类型_Excel表