tbwshc

          #

          10g中DBA_TAB_STATISTICS的STATTYPE_LOCKED列對分區鎖定顯示為空的解決

          Oracle10g的DBA_TAB_STATISTICS視圖的STATTYPE_LOCKED列沒有正確的顯示結果。

          10g中DBA_TAB_STATISTICS的STATTYPE_LOCKED列對分區鎖定顯示為空:http://yangtingkun.net/?p=1023

           

           

          上文提到了DBA_TAB_STATISTICS中的STATTYPE_LOCKED列在10g中對于分tb區鎖定統計信息顯示為空,那么在10g中有沒有辦法獲取到正確的結果呢:

          SQL> select table_name, partition_name, last_analyzed, stattype_locked
           2 from dba_tab_statistics
           3 where wner = user
           4 and table_name = 'T_PART';

          TABLE_NAME                     PARTITION_NAME                 LAST_ANAL STATT
          ------------------------------ ------------------------------ --------- -----
          T_PART                                                        16-JUL-12
          T_PART                         P1
          T_PART                         P2                             16-JUL-12
          T_PART                         PMAX                           16-JUL-12

          SQL> exec dbms_stats.gather_table_stats(user, 'T_PART', partname => 'P1')
          BEGIN dbms_stats.gather_table_stats(user, 'T_PART', partname => 'P1'); END;

          *
          ERROR at line 1:
          ORA-20005: object statistics are locked (stattype = ALL)
          ORA-06512: at "SYS.DBMS_STATS", line 15027
          ORA-06512: at "SYS.DBMS_STATS", line 15049
          ORA-06512: at line 1

          顯然雖然Oracle在DBA_TAB_STATISTICS視圖中沒有正確的顯示分區的鎖定狀態,但是Oracle在內部確實記錄了分區的鎖定狀態,既然Oracle記錄了這個信息,就有辦法將這個信息顯示出來。

          既然11g能夠顯示該列的值,最簡單的方法莫過于對比10g和11g中DBA_TAB_STATISTICS視圖的區別,10g視圖的結果:

          SQL> select text from dba_views where view_name = 'DBA_TAB_STATISTICS';

          TEXT
          --------------------------------------------------------------------------------
          SELECT /* TABLES */
              u.name, o.name, NULL, NULL, NULL, NULL, 'TABLE', t.rowcnt,
          .
          .
          .
              decode(bitand(t.trigflag, 67108864) + bitand(t.trigflag, 134217728),
                     0, NULL, 67108864, 'DATA', 134217728, 'CACHE', 'ALL'),
          .
          .
          .
           FROM
              sys.user$ u, sys.obj$ o, sys.tab$ t, sys.tab_stats$ ts, sys.mon_mods_all$ m
           WHERE
          .
          .
          .
           UNION ALL
           SELECT /* PARTITIONS, NOT IOT */
              u.name, o.name, o.subname, tp.part#, NULL, NULL, 'PARTITION',
          .
          .
          .
              decode(bitand(tab.trigflag, 67108864) + bitand(tab.trigflag, 134217728),
                     0, NULL, 67108864, 'DATA', 134217728, 'CACHE', 'ALL'),
          .
          .
          .
           FROM
              sys.user$ u, sys.obj$ o, sys.tabpartv$ tp, sys.tab_stats$ ts, sys.tab$ tab,
              sys.mon_mods_all$ m
           WHERE
          .
          .
          .
           UNION ALL
           SELECT /* IOT Partitions */
              u.name, o.name, o.subname, tp.part#, NULL, NULL, 'PARTITION',
          .
          .
          .
              decode(bitand(tab.trigflag, 67108864) + bitand(tab.trigflag, 134217728),
                     0, NULL, 67108864, 'DATA', 134217728, 'CACHE', 'ALL'),
          .
          .
          .
           FROM
              sys.user$ u, sys.obj$ o, sys.tabpartv$ tp, sys.tab$ tab, sys.mon_mods_all$ m

           WHERE
          .
          .
          .
           UNION ALL
           SELECT /* COMPOSITE PARTITIONS */
              u.name, o.name, o.subname, tcp.part#, NULL, NULL, 'PARTITION',
          .
          .
          .
              decode(bitand(tab.trigflag, 67108864) + bitand(tab.trigflag, 134217728),
                     0, NULL, 67108864, 'DATA', 134217728, 'CACHE', 'ALL'),
          .
          .
          .
           FROM
              sys.user$ u, sys.obj$ o, sys.tabcompartv$ tcp,
              sys.tab_stats$ ts, sys.tab$ tab, sys.mon_mods_all$ m
           WHERE
          .
          .
          .
           UNION ALL
           SELECT /* SUBPARTITIONS */
              u.name, po.name, po.subname, tcp.part#, so.subname, tsp.subpart#,
          .
          .
          .
              decode(bitand(tab.trigflag, 67108864) + bitand(tab.trigflag, 134217728),
                     0, NULL, 67108864, 'DATA', 134217728, 'CACHE', 'ALL'),
          .
          .
          .
           FROM
              sys.user$ u, sys.obj$ po, sys.obj$ so, sys.tabcompartv$ tcp,
              sys.tabsubpartv$ tsp, sys.tab_stats$ ts, sys.tab$ tab, sys.mon_mods_all$ m
           WHERE
          .
          .
          .
           UNION ALL
           SELECT /* FIXED TABLES */
              'SYS', t.kqftanam, NULL, NULL, NULL, NULL, 'FIXED TABLE',
          .
          .
          .

          對比一下11g的查詢結果tb

          SQL> select text from dba_views where view_name = 'DBA_TAB_STATISTICS';

          TEXT
          --------------------------------------------------------------------------------
          SELECT /* TABLES */
              u.name, o.name, NULL, NULL, NULL, NULL, 'TABLE', t.rowcnt,
          .
          .
          .
              decode(bitand(t.trigflag, 67108864) + bitand(t.trigflag, 134217728),
                     0, NULL, 67108864, 'DATA', 134217728, 'CACHE', 'ALL'),
          .
          .
          .
           FROM
              sys.user$ u, sys.obj$ o, sys.tab$ t, sys.tab_stats$ ts, sys.mon_mods_all$ m
           WHERE
          .
          .
          .
           UNION ALL
           SELECT /* PARTITIONS, NOT IOT */
              u.name, o.name, o.subname, tp.part#, NULL, NULL, 'PARTITION',
          .
          .
          .
              decode(
                /*
                 * Following decode returns 1 if DATA stats locked for partition
                 * or at table level
                 */
                decode(bitand(tab.trigflag, 67108864) + bitand(tp.flags, 32), 0, 0, 1) +
                /*
                 * Following decode returns 2 if CACHE stats locked for partition
                 * or at table level
                 */
                decode(bitand(tab.trigflag, 134217728) + bitand(tp.flags, 64), 0, 0, 2),
                /* if 0 => not locked, 3 => data and cache stats locked */
                0, NULL, 1, 'DATA', 2, 'CACHE', 'ALL'),
          .
          .
          .
           FROM
              sys.user$ u, sys.obj$ o, sys.tabpartv$ tp, sys.tab_stats$ ts, sys.tab$ tab,
              sys.mon_mods_all$ m
          .
          .
          .
           UNION ALL
           SELECT /* IOT Partitions */
              u.name, o.name, o.subname, tp.part#, NULL, NULL, 'PARTITION',
          .
          .
          .
              decode(
                /*
                 * Following decode returns 1 if DATA stats locked for partition
                 * or at table level
                 */
                decode(bitand(tab.trigflag, 67108864) + bitand(tp.flags, 32), 0, 0, 1) +
                /*
                 * Following decode returns 2 if CACHE stats locked for partition
                 * or at table level
                 */
                decode(bitand(tab.trigflag, 134217728) + bitand(tp.flags, 64), 0, 0, 2),
                /* if 0 => not locked, 3 => data and cache stats locked */
                0, NULL, 1, 'DATA', 2, 'CACHE', 'ALL'),
          .
          .
          .
           FROM
              sys.user$ u, sys.obj$ o, sys.tabpartv$ tp, sys.tab$ tab, sys.mon_mods_all$ m

           WHERE
          .
          .
          .
           UNION ALL
           SELECT /* COMPOSITE PARTITIONS */
              u.name, o.name, o.subname, tcp.part#, NULL, NULL, 'PARTITION',
          .
          .
          .
              decode(
                /*
                 * Following decode returns 1 if DATA stats locked for partition
                 * or at table level
                 */
                decode(bitand(tab.trigflag, 67108864) + bitand(tcp.flags, 32), 0, 0, 1) +
                /*
                 * Following decode returns 2 if CACHE stats locked for partition
                 * or at table level
                 */
                decode(bitand(tab.trigflag, 134217728) + bitand(tcp.flags, 64), 0, 0, 2),
                /* if 0 => not locked, 3 => data and cache stats locked */
                0, NULL, 1, 'DATA', 2, 'CACHE', 'ALL'),
          .
          .
          .
           FROM
              sys.user$ u, sys.obj$ o, sys.tabcompartv$ tcp,
              sys.tab_stats$ ts, sys.tab$ tab, sys.mon_mods_all$ m
           WHERE
          .
          .
          .
           UNION ALL
           SELECT /* SUBPARTITIONS */
              u.name, po.name, po.subname, tcp.part#, so.subname, tsp.subpart#,
          .
          .
          .
              decode(
                /*
                 * Following decode returns 1 if DATA stats locked for partition
                 * or at table level.
                 * Note that dbms_stats does n't allow locking subpartition stats.
                 * If the composite partition is locked, all subpartitions are
                 * considered locked. Hence decode checks for tcp entry.
                 */
                decode(bitand(tab.trigflag, 67108864) + bitand(tcp.flags, 32), 0, 0, 1) +
                /*
                 * Following decode returns 2 if CACHE stats locked for partition
                 * or at table level
                 */
                decode(bitand(tab.trigflag, 134217728) + bitand(tcp.flags, 64), 0, 0, 2),
                /* if 0 => not locked, 3 => data and cache stats locked */
                0, NULL, 1, 'DATA', 2, 'CACHE', 'ALL'),
          .
          .
          .
           FROM
              sys.user$ u, sys.obj$ po, sys.obj$ so, sys.tabcompartv$ tcp,
              sys.tabsubpartv$ tsp, sys.tab_stats$ ts, sys.tab$ tab, sys.mon_mods_all$ m
           WHERE
          .
          .
          .
           UNION ALL
           SELECT /* FIXED TABLES */
          .
          .

          顯然在11g中Oracle對于分區鎖定的顯示采用了新的算法,那么可以仿照11g中建立一個視圖,來解決10g中分區顯示存在錯誤的問題:

          SQL> CREATE OR REPLACE VIEW DBA_TAB_STATISTICS_LOCK
           2 (OWNER, TABLE_NAME, PARTITION_NAME,
           3 SUBPARTITION_NAME, OBJECT_TYPE, STATTYPE_LOCKED)
           4 AS
           5 SELECT u.name, o.name, NULL, NULL, 'TABLE',
           6      decode(bitand(t.trigflag, 67108864) + bitand(t.trigflag, 134217728),
           7             0, NULL, 67108864, 'DATA', 134217728, 'CACHE', 'ALL')
           8    FROM sys.user$ u, sys.obj$ o, sys.tab$ t
           9    WHERE o.owner# = u.user#
           10      and o.obj# = t.obj#
           11      and bitand(t.property, 1) = 0
           12      and o.subname IS NULL
           13      and o.namespace = 1 and o.remoteowner IS NULL and o.linkname IS NULL
           14      and bitand(o.flags, 128) = 0
           15 UNION ALL
           16 SELECT u.name, o.name, o.subname, NULL, 'PARTITION',
           17      decode(
           18        decode(bitand(tab.trigflag, 67108864) + bitand(tp.flags, 32), 0, 0, 1) +
           19        decode(bitand(tab.trigflag, 134217728) + bitand(tp.flags, 64), 0, 0, 2),
           20        0, NULL, 1, 'DATA', 2, 'CACHE', 'ALL')
           21    FROM sys.user$ u, sys.obj$ o, sys.tabpartv$ tp, sys.tab$ tab
           22    WHERE o.owner# = u.user#
           23      and o.obj# = tp.obj#
           24      and tp.bo# = tab.obj#
           25      and bitand(tab.property, 64) = 0
           26      and o.namespace = 1 and o.remoteowner IS NULL and o.linkname IS NULL
           27      and bitand(o.flags, 128) = 0
           28 UNION ALL
           29    SELECT u.name, o.name, o.subname, NULL, 'PARTITION',
           30      decode(
           31        decode(bitand(tab.trigflag, 67108864) + bitand(tp.flags, 32), 0, 0, 1) +
           32        decode(bitand(tab.trigflag, 134217728) + bitand(tp.flags, 64), 0, 0, 2),
           33        0, NULL, 1, 'DATA', 2, 'CACHE', 'ALL')
           34   FROM sys.user$ u, sys.obj$ o, sys.tabpartv$ tp, sys.tab$ tab
           35    WHERE o.owner# = u.user#
           36      and o.obj# = tp.obj#
           37      and tp.bo# = tab.obj#
           38      and bitand(tab.property, 64) = 64
           39      and o.namespace = 1 and o.remoteowner IS NULL and o.linkname IS NULL
           40      and bitand(o.flags, 128) = 0
           41 UNION ALL
           42    SELECT u.name, o.name, o.subname, NULL, 'PARTITION',
           43      decode(
           44        decode(bitand(tab.trigflag, 67108864) + bitand(tcp.flags, 32), 0, 0, 1) +
           45        decode(bitand(tab.trigflag, 134217728) + bitand(tcp.flags, 64), 0, 0, 2),
           46        0, NULL, 1, 'DATA', 2, 'CACHE', 'ALL')
           47    FROM sys.user$ u, sys.obj$ o, sys.tabcompartv$ tcp, sys.tab$ tab
           48    WHERE o.owner# = u.user#
           49      and o.obj# = tcp.obj#
           50      and tcp.bo# = tab.obj#
           51      and o.namespace = 1 and o.remoteowner IS NULL and o.linkname IS NULL
           52      and bitand(o.flags, 128) = 0
           53 UNION ALL
           54    SELECT u.name, po.name, po.subname, so.subname, 'SUBPARTITION',
           55      decode(
           56        decode(bitand(tab.trigflag, 67108864) + bitand(tcp.flags, 32), 0, 0, 1) +
           57        decode(bitand(tab.trigflag, 134217728) + bitand(tcp.flags, 64), 0, 0, 2),
           58        0, NULL, 1, 'DATA', 2, 'CACHE', 'ALL')
           59    FROM sys.user$ u, sys.obj$ po, sys.obj$ so, sys.tabcompartv$ tcp, sys.tabsubpartv$ tsp, sys.tab$ tab
           60    WHERE so.obj# = tsp.obj#
           61      and po.obj# = tcp.obj#
           62      and tcp.obj# = tsp.pobj#
           63      and tcp.bo# = tab.obj#
           64      and u.user# = po.owner#
           65      and bitand(tab.property, 64) = 0
           66      and po.namespace = 1 and po.remoteowner IS NULL and po.linkname IS NULL
           67      and bitand(po.flags, 128) = 0
           68    ;

          View created.

          SQL> select table_name, partition_name, object_type, stattype_locked
            2 from dba_tab_statistics_lock
           3 where wner = 'TEST'
           4 and table_name = 'T_PART';

          TABLE_NAME                     PARTITION_NAME                 OBJECT_TYPE STATT
          ------------------------------ ------------------------------ ------------ -----
          T_PART                                                        TABLE
          T_PART                         P1                             PARTITION    ALL
          T_PART                         P2                             PARTITION
          T_PART                         PMAX                           PARTITION

          使用新創建的這個視圖,就可以解決鎖定分區的統計信息顯示問題。

           


          posted @ 2012-08-20 13:08 chen11-1| 編輯 收藏

          分區表UNUSED列后的EXCHANGE PARTITION操作

          碰到一個有意思的問題,如果分區表執行過SET UNUSED操作,那么是否還可以進行分區的EXCHANGE操作。

           

           

          一個簡單的測試就可以說明這個問題:

          SQL> create table t_part_unused
           2 (id number, name varchar2(30), other varchar2(30))
           3 partition by range (id)
           4 (partition p1 values less than (10),
           5 partition pmax values less than (maxvalue));

          Table created.

          SQL> insert into t_part_unused
           2 select rownum, table_name, 'abc'
           3 from user_tables;

          48 rows created.

          SQL> commit;

          Commit complete.

          SQL> alter table t_part_unused set unused (other);

          Table altered.

          SQL> desc t_part_unused
           Name                                    Null?   Type
           ---------------------------------------- -------- ------------------------
           ID                                               NUMBER
           NAME                                             VARCHAR2(30)

          SQL> create table t_temp_unused as
           2 select *
           3 from t_part_unused
           4 where 1 = 2;

          Table created.

          SQL> desc t_temp_unused
           Name                                    Null?   Type
           ---------------------------------------- -------- ------------------------
           ID                                               NUMBER
           NAME                                             VARCHAR2(30)

          SQL> alter table t_part_unused
           2 exchange partition p1
           3 with table t_temp_unused;
          with table t_temp_unused
                    *
          ERROR at line 3:
          ORA-14097: column type or size mismatch in ALTER TABLE EXCHANGE PARTITION TB


          SQL> alter table t_temp_unused add (other varchar2(30));

          Table altered.

          SQL> alter table t_part_unused
           2 exchange partition p1
           3 with table t_temp_unused;
          with table t_temp_unused
                    *
          ERROR at line 3:
          ORA-14096: tables in ALTER TABLE EXCHANGE PARTITION must have the same number of columns


          SQL> alter table t_temp_unused set unused (other);

          Table altered.

          SQL> alter table t_part_unused
           2 exchange partition p1
           3 with table t_temp_unused;

          Table altered.

          很明顯執行了SET UNUSED操作后的表,和普通的表是存在區別的,這種區別導致要求進行EXCHANGE的表必須同樣執行SET UNUSED操作,否則就無法執行EXCHANGE的操作。

          當目標表中不包含SETE UNUSED的列時,EXCHANGE操作會出現ORA-14097的錯誤,而如果把列添加到目標表,則會報錯ORA-14096,必須在目標表同樣對列執行SET UNUSED操作,才能通過EXCHANGE之前的檢查。

          其實這也不難理解,執行SET UNUSED命令后,數據字典雖然發生了改變,但是表上的數據并沒有刪除,而EXCHANGE操作只是將兩個段的數據字典進行互換,因此如果目標表上缺少SET UNUSED列,是無法執行EXCHANGE操作的。

          解決問題的方法有兩個,第一個就是例子中展示的可以在目標表上建立列然后同樣的執行SET UNUSED操作;另外的一個方法就是對于SET UNUSED列執行DROP COLUMN操作,徹底刪除該列。

           


          posted @ 2012-08-17 14:56 chen11-1| 編輯 收藏

          小議ROWNUM

          如何使用ROWNUM是個老生常談的問題了,本來沒有打算專門強調這個問題,但是最近在看Oracle的官方PL/SQL文檔時發現了一個嚴重的錯誤,借這個機會還是簡單說一下。

           

           

          首先來看Oracle文檔的描述,在10.2的PL/SQL文檔中,Oracle關于PL/SQL中直接使用SELECT的查詢描述為:

          Selecting At Most One Row: SELECT INTO Statement
          If you expect a query to only return one row, you can write a regular SQL SELECT statement with an additional INTO clause specifying the PL/SQL variable to hold the result.
          If the query might return more than one row, but you do not care about tb values after the first, you can restrict any result set to a single row by comparing the ROWNUM value. If the query might return no rows at all, use an exception handler to specify any actions to take when no data is found.

          這個描述是沒有問題的,但是到了11.2中,文檔的描述變成了:

          Single-Row Result Sets
          If you expect the query to return only one row, then use the SELECT INTO statement to store values from that row in either one or more scalar variables (see "Assigning Values to Variables with the SELECT INTO Statement") or one record variable (see "SELECT INTO Statement for Assigning Row to Record Variable").
          If the query might return multiple rows, but you care about only the nth row, then restrict the result set to that row with the clause WHERE ROWNUM=n. For more information about the ROWNUM pseudocolumn, see Oracle Database SQL Language Reference.

          第一個反應是不是我看錯了,居然可以通過WHERE ROWNUM = N來限制只返回第N條記錄 ,再仔細看了一遍,并和10g的文檔對比,發現11.2和10.2中的不同。于是第二個反應是Oracle在11.2中提供了新特性,使得PL/SQL語句中直接SELECT可以通過WHERE ROWNUM來直接控制游標,于是特意在11.2上進行了測試,發現結果和10.2上沒有區別,ROWNUM = N是行不通的,除非N等于1。

          SQL> select * from v$version;

          BANNER
          ------------------------------------------------------------------------------
          Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
          PL/SQL Release 11.2.0.1.0 - Production
          CORE   11.2.0.1.0     Production
          TNS for 32-bit Windows: Version 11.2.0.1.0 - Production
          NLSRTL Version 11.2.0.1.0 - Production

          SQL> select * from tab;

          TNAME                         TABTYPE CLUSTERID
          ------------------------------ ------- ----------
          COMPANIES                     TABLE
          MLOG$_T_F                     TABLE
          MLOG$_T_P                     TABLE
          MV_T_ORACLE                   TABLE
          SERVICES                      TABLE
          SERVICE_RATES                 TABLE
          SERVICE_USAGE                 TABLE
          SERVICE_USERS                 TABLE
          T                             TABLE
          T_DEFER                       TABLE
          T_F                           TABLE
          T_LOAD_LOB                    TABLE
          T_P                           TABLE
          T_PART                        TABLE

          已選擇14行。

          SQL> set serverout on
          SQL> declare
           2 v_name varchar2(30);
           3 begin
           4 select tname into v_name from tab where rownum = 5;
           5 dbms_output.put_line(v_name);
           6 exception
           7 when no_data_found then
           8 dbms_output.put_line('rownum equal the num bigger than 1 is incorrect!');
           9 end;
           10 /
          rownum equal the num bigger than 1 is incorrect!

          PL/SQL過程已成功完成。

          顯然Oracle文檔這里出現了嚴重的錯誤,如果要使用ROWNUM來控制返回第幾行結果,那么至少需要2層嵌套查詢才可以。

          最后簡單總結一下ROWNUM,很多人都知道ROWNUM只適用于小于或小于等于,如果進行等于判斷,那么只能等于1,不能進行大于的比較。但是卻并不了解造成這種限制條件的機制是什么。

          其實ROWNUM的返回很簡單,ROWNUM總是從1開始,不管當前的記錄是否滿足查詢結果,ROWNUM返回的值都是1,如果這條記錄的值最終滿足所有的條件,那么ROWNUM會遞加,下一條記錄的ROWNUM會返回2,否則下一條記錄的ROWNUM仍然返回1。

          理解了這一點,就清楚為什么一般的ROWNUM大于某個值或等于某個不為1的值是無法返回結果的,因此對于每條記錄的ROWNUM都是1,而ROWNUM為1不滿足查詢的結果,所以下一條記錄的ROWNUM不會遞增,仍然是1,因此所有的記錄都不滿足條件。

          了解了原理,就可以很容易的寫出ROWNUM大于某值的例子:

          SQL> select * from tab where rownum = 1 or rownum > 1;

          TNAME                         TABTYPE CLUSTERID
          ------------------------------ ------- ----------
          COMPANIES                     TABLE
          MLOG$_T_F                     TABLE
          MLOG$_T_P                     TABLE
          MV_T_ORACLE                   TABLE
          SERVICES                      TABLE
          SERVICE_RATES                 TABLE
          SERVICE_USAGE                 TABLE
          SERVICE_USERS                 TABLE
          T                             TABLE
          T_DEFER                       TABLE
          T_F                           TABLE
          T_LOAD_LOB                    TABLE
          T_P                           TABLE
          T_PART                        TABLE

          posted @ 2012-08-17 14:53 chen11-1| 編輯 收藏

          物化視圖刷新出現臨時空間不足的問題

          朋友解決一個物化視圖刷新時碰到的問題。

           

           

          數據庫版本為10.2.0.4,一次本地聚集物化視圖的快速刷新執行了3個小時后出現了臨時表空間不足的錯誤:

          ORA-12008: error in materialized view refresh path
          ORA-01652: unable to extend temp segment by 32 in tablespace TEMP01

          這個物化視圖以前的刷新是正常的,只是最近偶爾會出現這個錯誤。上次出現這個錯誤,tb通過添加臨時數據文件并重啟數據庫解決了問題。目前數據庫的臨時表空間已經超過1T的大小,如果不找到問題的原因,僅靠通過添加臨時文件顯然是不現實的。

          通過跟蹤刷新物化視圖的會話,發現問題確實出在物化視圖的快速刷新操作上,而會話的等待事件主要集中在臨時表空間的寫操作上:direct path write temp。

          做了一個awrsql報告,檢查了SQL語句和執行計劃。由于這個SQL本身相對比較復雜,這就使得快速刷新的MERGE語句更加復雜,簡單格式化后,語句長度超過300行,這里就不列出來了。這個SQL的執行計劃為:

          Execution Plan
          Id  Operation  Name  Rows  Bytes  TempSpc Cost (%CPU) Time
          0  MERGE STATEMENT      129K(100) 
          1  MERGE  MV_NW_KHXX_YDKH_ALL      
          2  VIEW       
          3  NESTED LOOPS OUTER   4  1592   129K (1) 00:38:46
          4  VIEW   4  1084   129K (1) 00:38:46
          5  TEMP TABLE TRANSFORMATION       
          6  LOAD AS SELECT       
          7  VIEW   33  3300   123 (1) 00:00:03
          8  WINDOW SORT   33  6600   123 (1) 00:00:03
          9  TABLE ACCESS FULL  MLOG$_MV_NW_KHXX_YDKH_2  33  6600   122 (0) 00:00:03
          10  LOAD AS SELECT       
          11  VIEW   19151  2244K  3533 (1) 00:01:04
          12  WINDOW SORT   19151  4114K 9376K 3533 (1) 00:01:04
          13  TABLE ACCESS FULL  MLOG$_MV_NW_KHXX_YDKH_1  19151  4114K  3169 (1) 00:00:58
          14  SORT GROUP BY   4  1040   125K (1) 00:37:40
          15  VIEW   4  1040   125K (1) 00:37:40
          16  UNION-ALL       
          17  HASH JOIN   1  289   21023 (1) 00:06:19
          18  HASH JOIN   1  220   20984 (1) 00:06:18
          19  TABLE ACCESS FULL  MLOG$_DW_YH_JBXX  1  171   20982 (1) 00:06:18
          20  VIEW   33  1617   2 (0) 00:00:01
          21  TABLE ACCESS FULL  SYS_TEMP_0FD9D6744_E9EB0662  33  2013   2 (0) 00:00:01
          22  VIEW   19151  1290K  38 (0) 00:00:01
          23  TABLE ACCESS FULL  SYS_TEMP_0FD9D6745_E9EB0662  19151  1514K  38 (0) 00:00:01
          24  HASH JOIN ANTI   1  281   41338 (1) 00:12:25
          25  HASH JOIN   1  267   41300 (1) 00:12:24
          26  HASH JOIN   1  220   20984 (1) 00:06:18
          27  TABLE ACCESS FULL  MLOG$_DW_YH_JBXX  1  171   20982 (1) 00:06:18
          28  VIEW   33  1617   2 (0) 00:00:01
          29  TABLE ACCESS FULL  SYS_TEMP_0FD9D6744_E9EB0662  33  2013   2 (0) 00:00:01
          30  MAT_VIEW ACCESS FULL  MV_NW_KHXX_YDKH_1  9008K 403M  20279 (1) 00:06:06
          31  VIEW   19151  261K  38 (0) 00:00:01
          32  TABLE ACCESS FULL  SYS_TEMP_0FD9D6745_E9EB0662  19151  1514K  38 (0) 00:00:01
          33  HASH JOIN ANTI   1  284   21437 (1) 00:06:26
          34  HASH JOIN   1  270   21435 (1) 00:06:26
          35  HASH JOIN   1  240   21020 (1) 00:06:19
          36  TABLE ACCESS FULL  MLOG$_DW_YH_JBXX  1  171   20982 (1) 00:06:18
          37  VIEW   19151  1290K  38 (0) 00:00:01
          38  TABLE ACCESS FULL  SYS_TEMP_0FD9D6745_E9EB0662  19151  1514K  38 (0) 00:00:01
          39  MAT_VIEW ACCESS FULL  MV_NW_KHXX_YDKH_2  283K 8293K  413 (2) 00:00:08
          40  VIEW   33  462   2 (0) 00:00:01
          41  TABLE ACCESS FULL  SYS_TEMP_0FD9D6744_E9EB0662  33  2013   2 (0) 00:00:01
          42  HASH JOIN ANTI   1  276   41753 (1) 00:12:32
          43  HASH JOIN ANTI   1  262   41714 (1) 00:12:31
          44  HASH JOIN   1  248   41711 (1) 00:12:31
          45  HASH JOIN   1  201   21396 (1) 00:06:26
          46  TABLE ACCESS FULL  MLOG$_DW_YH_JBXX  1  171   20982 (1) 00:06:18
          47  MAT_VIEW ACCESS FULL  MV_NW_KHXX_YDKH_2  283K 8293K  413 (2) 00:00:08
          48  MAT_VIEW ACCESS FULL  MV_NW_KHXX_YDKH_1  9008K 403M  20279 (1) 00:06:06
          49  VIEW   33  462   2 (0) 00:00:01
          50  TABLE ACCESS FULL  SYS_TEMP_0FD9D6744_E9EB0662  33  2013   2 (0) 00:00:01
          51  VIEW   19151  261K  38 (0) 00:00:01
          52  TABLE ACCESS FULL  SYS_TEMP_0FD9D6745_E9EB0662  19151  1514K  38 (0) 00:00:01
          53  MAT_VIEW ACCESS BY INDEX ROWID MV_NW_KHXX_YDKH_ALL  1  127   2 (0) 00:00:01
          54  INDEX UNIQUE SCAN  I_SNAP$_MV_NW_KHXX_YDKH_AL  1    1 (0) 00:00:01
           

          從執行計劃上看出一些疑問,MLOG$_DW_YH_JBXX表的結果只有1行,而實際上這張表的大小超過100W。

          在默認情況下,收集SCHEMA的統計信息是不會收集物化視圖日志的,而且即使Oracle收集統計信息時可以收集物化視圖日志的統計信息,對于當前的情況,也無濟于事。因為當前刷新的物化視圖是第一個嵌套物化視圖,它建立在其他兩個物化視圖的基礎上,也就是說,只有刷新了其他兩個物化視圖之后,對應的物化視圖日志中才會有記錄,而其他時候,物化視圖日志中的記錄都是0。

          其實現在問題已經確定了,由于物化視圖日志沒有統計信息,Oracle認為物化視圖日志中記錄很少,產生了一個最外層為NESTED LOOP的執行計劃,導致刷新效率十分低下。對于這種情況,其實可以通過一次完全刷新來解決問題,但是對于當前的情況,仍然是不可行的。因為這個物化視圖是數據倉庫系統中的一個中間結果表,下游還有很多物化視圖以及其他系統依賴于當前物化視圖的增量數據。一旦這個物化視圖執行了完全刷新,就會導致所有依賴當前對象的下游物化視圖的增量刷新變成了完全刷新。

          當前快速刷新碰到的問題其實就是Oracle的默認策略認為物化視圖日志中的數據量應該遠小于基表的數據量,這樣快速刷新才會有性能上的優勢,但是當前情況下,物化視圖日志的數據量和基表的數據量處于同一個數量級,因此缺少統計信息后,快速刷新的執行計劃變得十分的低效。而如果采用完全刷新來解決當前物化視圖的問題,那么實際上是把這個問題擴大到下游所有有依賴關系的物化視圖上。

          為了解決這個問題,首先想到的是optimizer_dynamic_samping參數,通過設置會話級的參數,控制物化視圖日志刷新之前,進行詳細的動態統計信息采樣,使之可以得到一個適合的執行計劃。

          但是將optimizer_dynamic_samping設置為10后,發現對MLOG$_DW_YH_JBXX表不起任何作用,刷新的執行計劃中,MLOG$_DW_YH_JBXX表的行數仍然為1。

          看來沒有別的辦法,只有手工顯示的對物化視圖日志表執行統計信息的收集工作,當統計信息收集完成后,再次運行物化視圖的快速刷新,結果用了不到10分鐘的時間,物化視圖就刷新成功了。

          這次執行計劃變為:

          Execution Plan

          Id  Operation  Name  Rows  Bytes  TempSpc Cost (%CPU) Time
          0  MERGE STATEMENT      141K(100) 
          1  MERGE  MV_NW_KHXX_YDKH_ALL      
          2  VIEW       
          3  HASH JOIN OUTER   16997  6606K 4704K 141K (1) 00:42:19
          4  VIEW   16997  4498K  129K (1) 00:38:50
          5  TEMP TABLE TRANSFORMATION       
          6  LOAD AS SELECT       
          7  VIEW   33  3300   123 (1) 00:00:03
          8  WINDOW SORT   33  6600   123 (1) 00:00:03
          9  TABLE ACCESS FULL  MLOG$_MV_NW_KHXX_YDKH_2  33  6600   122 (0) 00:00:03
          10  LOAD AS SELECT       
          11  VIEW   19151  2244K  3533 (1) 00:01:04
          12  WINDOW SORT   19151  4114K 9376K 3533 (1) 00:01:04
          13  TABLE ACCESS FULL  MLOG$_MV_NW_KHXX_YDKH_1  19151  4114K  3169 (1) 00:00:58
          14  SORT GROUP BY   16997  4315K  125K (1) 00:37:44
          15  VIEW   16997  4315K  125K (1) 00:37:44
          16  UNION-ALL       
          17  HASH JOIN   267  50196   21078 (1) 00:06:20
          18  HASH JOIN   191  26549   21076 (1) 00:06:20
          19  TABLE ACCESS FULL  MLOG$_DW_YH_JBXX  11859  810K  21037 (1) 00:06:19
          20  VIEW   19151  1290K  38 (0) 00:00:01
          21  TABLE ACCESS FULL  SYS_TEMP_0FD9D674D_E9EB0662  19151  1514K  38 (0) 00:00:01
          22  VIEW   33  1617   2 (0) 00:00:01
          23  TABLE ACCESS FULL  SYS_TEMP_0FD9D674C_E9EB0662  33  2013   2 (0) 00:00:01
          24  HASH JOIN   16188  2845K  41394 (1) 00:12:26
          25  VIEW   33  1617   2 (0) 00:00:01
          26  TABLE ACCESS FULL  SYS_TEMP_0FD9D674C_E9EB0662  33  2013   2 (0) 00:00:01
          27  HASH JOIN RIGHT ANTI   11594  1483K  41391 (1) 00:12:26
          28  VIEW   19151  261K  38 (0) 00:00:01
          29  TABLE ACCESS FULL  SYS_TEMP_0FD9D674D_E9EB0662  19151  1514K  38 (0) 00:00:01
          30  HASH JOIN   11594  1324K  41352 (1) 00:12:25
          31  TABLE ACCESS FULL  MLOG$_DW_YH_JBXX  11859  810K  21037 (1) 00:06:19
          32  MAT_VIEW ACCESS FULL  MV_NW_KHXX_YDKH_1  9008K 403M  20279 (1) 00:06:06
          33  HASH JOIN ANTI   9  1647   21492 (1) 00:06:27
          34  HASH JOIN   9  1521   21490 (1) 00:06:27
          35  HASH JOIN   191  26549   21076 (1) 00:06:20
          36  TABLE ACCESS FULL  MLOG$_DW_YH_JBXX  11859  810K  21037 (1) 00:06:19
          37  VIEW   19151  1290K  38 (0) 00:00:01
          38  TABLE ACCESS FULL  SYS_TEMP_0FD9D674D_E9EB0662  19151  1514K  38 (0) 00:00:01
          39  MAT_VIEW ACCESS FULL  MV_NW_KHXX_YDKH_2  283K 8293K  413 (2) 00:00:08
          40  VIEW   33  462   2 (0) 00:00:01
          41  TABLE ACCESS FULL  SYS_TEMP_0FD9D674C_E9EB0662  33  2013   2 (0) 00:00:01
          42  HASH JOIN ANTI   533  93275   41808 (1) 00:12:33
          43  HASH JOIN RIGHT ANTI   533  85813   41769 (1) 00:12:32
          44  VIEW   33  462   2 (0) 00:00:01
          45  TABLE ACCESS FULL  SYS_TEMP_0FD9D674C_E9EB0662  33  2013   2 (0) 00:00:01
          46  HASH JOIN   533  78351   41766 (1) 00:12:32
          47  HASH JOIN   11594  1324K  41352 (1) 00:12:25
          48  TABLE ACCESS FULL  MLOG$_DW_YH_JBXX  11859  810K  21037 (1) 00:06:19
          49  MAT_VIEW ACCESS FULL MV_NW_KHXX_YDKH_1  9008K 403M  20279 (1) 00:06:06
          50  MAT_VIEW ACCESS FULL  MV_NW_KHXX_YDKH_2  283K 8293K  413 (2) 00:00:08
          51  VIEW   19151  261K  38 (0) 00:00:01
          52  TABLE ACCESS FULL  SYS_TEMP_0FD9D674D_E9EB0662  19151  1514K  38 (0) 00:00:01
          53  MAT_VIEW ACCESS FULL  MV_NW_KHXX_YDKH_ALL  1701K 206M  3888 (2) 00:01:10

          可以看到,最外層的執行計劃已經變成了HASH JOIN OUTER,而且雖然物化視圖日志MLOG$_DW_YH_JBXX的統計信息仍然少了2個數量級,但是比原本的1條記錄要靠譜多了。

          至此,問題得以解決,不過為了避免這種情況的再次發生,最好的辦法是將物化視圖日志的統計信息收集工作放到物化視圖刷新之前進行,這樣可以確保物化視圖的快速刷新可以得到最精確的統計信息,從而得到最優的執行計劃。

          posted @ 2012-08-17 09:36 chen11-1| 編輯 收藏

          提高代碼可讀性的十大注釋技巧

          很多程序員在寫代碼的時候往往都不注意代碼的可讀性,讓別人在閱讀代碼時花費更多的時間。其實,只要程序員在寫代碼的時候,注意為代碼加注釋,并以合理的格式為代碼加注釋,這樣就方便別人查看代碼,也方便自己以后查看了。下面分享十個加注釋的技巧:

          1. 逐層注釋

          為每個代碼塊添加注釋,并在每一層使用統一的注釋方法和風格。例如:

          針對每個類:包括摘要信息、作者信息、以及最近修改日期等;

          針對每個方法:包括用途、功能、參數和返回值等。

          在團隊工作中,采用標準化的注釋尤為重要。當然,使用注釋規范和工具(例如C#里的XML,Java里的Javadoc)可以tb更好的推動注釋工作完成得更好。

          2. 使用分段注釋

          如果有多個代碼塊,而每個代碼塊完成一個單一任務,則在每個代碼塊前添加一個注釋來向讀者說明這段代碼的功能。例子如下:

          // Check that all data records
          // are correct
          foreach (Record record in records)
          ...{
          if (rec.checkStatus()==Status.OK)
          ...{
          . . .
          }
          }
          // Now we begin to perform
          // transactions
          Context ctx = new ApplicationContext();
          ctx.BeginTransaction();
          . . .

          3. 在代碼行后添加注釋

          如果多行代碼的每行都要添加注釋,則在每行代碼后添加該行的注釋,這將很容易理解。例如:

          const MAX_ITEMS = 10; // maximum number of packets
          const MASK = 0x1F;    // mask bit TCP
          在分隔代碼和注釋時,有的開發者使用tab鍵,而另一些則使用空格鍵。然而由于tab鍵在各編輯器和IDE工具之間的表現不一致,因此最好的方法還是使用空格鍵。

          4. 不要侮辱讀者的智慧

          避免以下顯而易見的注釋:寫這些無用的注釋會浪費你的時間,并將轉移讀者對該代碼細節的理解。

          if (a == 5)      // if a equals 5
          counter = 0; // set the counter to zero

          5. 禮貌點

          避免粗魯的注釋,如:“注意,愚蠢的使用者才會輸入一個負數”或“剛修復的這個問題出于最初的無能開發者之手”。這樣的注釋能夠反映到它的作者是多么的拙劣,你也永遠不知道誰將會閱讀這些注釋,可能是:你的老板,客戶,或者是你剛才侮辱過的無能開發者。

          6. 關注要點

          不要寫過多的需要轉意且不易理解的注釋。避免ASCII藝術,搞笑,詩情畫意,hyperverbosity的注釋。簡而言之,保持注釋簡單直接。

          7. 使用一致的注釋風格

          一些人堅信注釋應該寫到能被非編程者理解的程度。而其他的人則認為注釋只要能被開發人員理解就行了。無論如何,Successful Strategies for Commenting Code已經規定和闡述了注釋的一致性和針對的讀者。就個人而言,我懷疑大部分非編程人員將會去閱讀代碼,因此注釋應該是針對其他的開發者而言。

          8. 使用特有的標簽

          在一個團隊工作中工作時,為了便于與其它程序員溝通,應該采用一致的標簽集進行注釋。例如,在很多團隊中用TODO標簽表示該代碼段還需要額外的工作。

          int Estimate(int x, int y)
          ...{
          // TODO: implement the calculations
          return 0;
          }
          注釋標簽切忌不要用于解釋代碼,它只是引起注意或傳遞信息。如果你使用這個技巧,記得追蹤并確認這些信息所表示的是什么。

          9. 在代碼時添加注釋

          在寫代碼時就添加注釋,這時在你腦海里的是清晰完整的思路。如果在代碼最后再添加同樣注釋,它將多花費你一倍的時間。而“我沒有時間寫注釋”,“我很忙”和“項目已經延期了”這都是不愿寫注釋而找的借口。一些開發者覺得應該write comments before code,用于理清頭緒。例如:

          public void ProcessOrder()
          ...{
          // Make sure the products are available
          // Check that the customer is valid
          // Send the order to the store
          // Generate bill
          }

          10. 為自己注釋代碼

          當注釋代碼時,要考慮到不僅將來維護你代碼的開發人員要看,而且你自己也可能要看。用Phil Haack大師的話來說就是:“一旦一行代碼顯示屏幕上,你也就成了這段代碼的維護者”。因此,對于我們寫得好(差)的注釋而言,我們將是第一個受益者(受害者)。

          posted @ 2012-08-16 14:50 chen11-1 閱讀(1760) | 評論 (2)編輯 收藏

          PHP-FPM高負載的解決辦法

          這里只是介紹了php-fpm的優化方法的,但一般情況下和nginx組合使用的時候,單獨優化其中一項的話,作用不是特別的大,同時還需要對nginx進行優化.nginx的做法方法參考:http://blog.haohtml.com/archives/6213.上面的優化前和優化后的圖,看得出前后差距還是特別的大的.

          導致nginx 502 bad gateway的PHP-CGI(FASTCGI)

          NGINX頻爆502 BAD GATEWAY的錯誤,看了網上的教程,仍沒有徹底解決。

          目前我總結的解決502 BAD GATEWAY的方式有:

          1.視服務器的性能,在php-fmp.conf里增加max_children的值,我目前用的15.

          2.用reload參數定時重載php-fpm。這個主要原因是php腳本執行時間過長造成的,重載php-fpm能杜絕這個問題。如何徹底解決php-cgi腳本占用大量內存從而導致502錯誤的產生還值得進一步探討,目前該做法不失為一種好辦法。

          具體的做法是,用crontab讓php-fpm平滑重啟,從而不影響PHP腳本的tb運行。

          */10 * * * * /usr/local/php/sbin/php-fpm reload

          =================== 優化設置 =========================


          When you running a highload website with PHP-FPM via FastCGI, the following tips may be useful to you : )

          如果您高負載網站使用PHP-FPM管理FastCGI,這些技巧也許對您有用:)

          1. Compile PHP’s modules as less as possible, the simple the best (fast);

          1.盡量少安裝PHP模塊,最簡單是最好(快)的

          2. Increas PHP FastCGI child number to 100 and even more. Sometime, 200 is OK! ( On 4GB memory server);

          2.把您的PHP FastCGI子進程數調到100或以上,在4G內存的服務器上200就可以

          注:我的1g測試機,開64個是最好的,建議使用壓力測試獲取最佳值

          3. Using SOCKET PHP FastCGI, and put into /dev/shm on Linux;

          3.使用socket連接FastCGI,linux操作系統可以放在 /dev/shm中

          注:在php-fpm.cnf里設置<value name=”listen_address”>/tmp/nginx.socket</value>就可以通過socket連接FastCGI了,/dev/shm是內存文件系統,放在內存中肯定會快了.記得這時也要在nginx里的配置里進行修改,保持一致.

          location ~ .*\.(php|php5)?$
          {
          #將Nginx與FastCGI的通信方式由TCP改為Unix Socket。TCP在高并發訪問下比Unix Socket穩定,但Unix Socket速度要比TCP快。
          fastcgi_pass  unix:/tmp/php-cgi.sock;
          #fastcgi_pass  127.0.0.1:9000;
          fastcgi_index index.php;
          include fcgi.conf;
          }

          4. Increase Linux “max open files”, using the following command (must be root):

          # echo ‘ulimit -HSn 65536′ >> /etc/profile
           # echo ‘ulimit -HSn 65536 >> /etc/rc.local
           # source /etc/profile 


          4.調高linux內核打開文件數量,可以使用這些命令(必須是root帳號)

          echo ‘ulimit -HSn 65536′ >> /etc/profile
           echo ‘ulimit -HSn 65536′ >> /etc/rc.local
           source /etc/profile 


          注:我是修改/etc/rc.local,加入ulimit -SHn 51200的

          5. Increase PHP-FPM open file description rlimit:

          # vi /path/to/php-fpm.conf
           Find “<value name=”rlimit_files”>1024</value>”
           Change 1024 to 4096 or higher number.
           Restart PHP-FPM.


          5. 增加 PHP-FPM 打開文件描述符的限制:

          # vi /path/to/php-fpm.conf
           找到“<value name=”rlimit_files”>1024</value>”
           把1024 更改為 4096 或者更高.
          重啟 PHP-FPM.


          6. Using PHP code accelerator, e.g eAccelerator, XCache. And set “cache_dir” to /dev/shm on Linux.
          6.使用php代碼加速器,例如 eAccelerator, XCache.在linux平臺上可以把`cache_dir`指向 /dev/shm

          至于其它的優化見李宴的bltbog一篇文章:http://blog.s135.com/post/375/

          This entry was posted in js框架 and tagged nginx, php-fpm by admin. Bookmark the permalink.

          One thought on “PHP-FPM高負載的解決辦法

          posted @ 2012-08-16 14:48 chen11-1| 編輯 收藏

          php下用iconv函數轉換字符編碼的問題

          昨天在調試 WAP 網站時發現,在增加了 GB2312 到 UTF-8 轉化以后,有些頁面顯示不正常了——有些頁面只有一半的內容,另一半被截掉了。因為被截掉的部分包含了<p>的后半個標簽</p>,因此整個頁面都顯示不出來,而報告錯誤。經過猜測、嘗試,最后終于把問題集中在了 iconv 函數上。在經過高人指點以后,發現這個函數的第二個參數,除了可以指定要轉化到的編碼以外,還可以增加兩個后綴://TRANSLIT 和 //IGNORE,其中 //TRANSLIT 會自動將不能直接轉化的字符變成一個或多個近似的字符,//IGNORE 會忽略掉不能轉化的字符,而默認效果是從第一個非法字符截斷。但是我嘗試了//TRANSLIT 和 //IGNORE 這兩個后綴,效果還是不對。于是我想問題可能不是出在這里。

          從 GB2312 到 UTF-8 轉化應該不會有不能轉化的字符,因為 UTF-8 的字符集完全包含了 GB2312 中的字符,所以我tb想大概是前面要轉化的字符集指定錯了,于是我嘗試著把 GB2312 改成 GBK

          $ary=addslashes(iconv("GB2312", "UTF-8", $ary));

          問題解決!雖然那兩個后綴在這里沒派上用場,不過也算學了一招,以后肯定會用到的。補記:改成 GBK 后,發現仍然有一封郵件的內容解析不正確。在另一位高人指點下,先換成 GB18030,問題依舊,然后改用 mb_convert_encoding 進行轉換,問題解決!不知道是 mb_convert_encoding 問題,還是我的系統問題,我用 mb_convert_encoding 時不支持 GB18030 編碼。另外,用 GBK 或者GB18030 作為輸入編碼,并在輸出編碼中加上 //IGNORE 后綴,用 iconv 函數也能解決那封含有錯誤編碼的郵件內容解析不正確的問題。不過用 mb_convert_encoding 可以指定多種輸入編碼,它會根據內容自動識別,這個比 iconv 要好的多。 這里可以將iconv改成從gbk到utf8的轉換,不使用gb2312.

          $ary=addslashes(iconv("GBK", "UTF-8", $ary));

          其實,同事在生成圖片文字水印的時候也遇到了這種問題,同事最初用的是GB2312字符集,結果直接報錯,說是字符串的offset有問題,但仔細檢查后卻沒有這種問題。后來才發現是直接調用的這個iconv轉換出錯了。
          原來的轉換是從gb2312往 UTF8轉換,表面上確實沒有什么問題,然而,現在的人特別愛裝酷,受影響的那位同志,用的是繁體字,繁體字的字庫大多情況是屬于GBK的,所以后來換成GBK后就正常了。
          估計以后再遇上用火星文的朋友,就真的只能使用andot提出的這種方法了。轉換成18030,再使用ignore參數。哈哈

          mbstring好象最初的版本里沒有使用,如果換成這個,估計代碼工作量非常大,先將就著點了

          posted @ 2012-08-16 14:45 chen11-1| 編輯 收藏

          忘記 VSS Admin 密碼 ! .

          一不小心將VSS 6 admin用戶的密碼忘記(再此證明我的粗心),Google了一番,找到以下信息

          the secret is to hack the um.dat file to remove the Admin password

          from offset 80 the bytes are (all numbers are hex)

          0:80  55 55 bc 7f 41 64 6d 69 6e 00 00 00 00 00 00 00
          0:90  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
          0:a0  00 00 00 00 90 6e 00 00 a8 01 00 00 00 00 00 00

          Just load the um.dat file into a hex editor and change the bytes from =
          offset 80 to exactly what is shown above. When the SourceSafe admin tool =
          starts it believes that the admin password has never been set.

          the hex values above are taken from a 'virgin' um.dat file

          of course, you didn't get this from me....and ALWAYS backup first (just =
          in case I'm wrong)

          有朋友看不懂,我用中文解釋一下

          如果忘記了密碼,打開你vss數據庫所在的文件夾,打開data目錄,
          找到um.dat文件,用hex編輯器打開編輯它,從offset 80的55 55 開始
          將值改為如上文所述的樣子,然后保存,這樣um.dat文件就回到了
          狀態(virgin ?  :)),然后打開vss admin,用admin用戶登錄,tb不需要
          密碼了。

          posted @ 2012-08-16 10:48 chen11-1| 編輯 收藏

          jquery.validate remote 和 自定義驗證方法

          $(function(){

          var validator = $("#enterRegForm").validate({
          debug:false, //調試模式取消submit的默認提交功能
          //errorClass: "error",//默認為錯誤的樣式類為:error
          //validClass: "check",//驗證成功后的樣式,默認字符串valid
          focusInvalid: true,//表單提交時,焦點會指向第一個沒有通過驗證的域
          //focusCleanup:true;//焦點指向錯誤域時,隱藏錯誤信息,不可與focusInvalid一起使用!
          onkeyup: true,
          errorElement: "div",
          submitHandler: function(form){ //表單提交句柄,為一回調函數,帶一個參數:form
          form.submit(); //提交表單
          },

          rules: {
          "enterprise.enName": {
          required: true,
          minlength: 6,
          remote:{
          url: "/nameServlet",     //后臺處理程序
          type: "get",               //數據發送方式
          dataType: "json",           //接受數據格式
          data: {                     //要傳遞的數據
          enName: function() {
          return $("#enName").val();
          }
          }

          }
          },

          "user.passWord":{
          required:true,
          rangelength:[6,18]
          },
          passWordConf:{
          required:true,
          rangelength:[6,18],
          equalTo:"#passWord" //此處的passWord 是<input id="passWord"> 一開始還以為是name的值呢,氣死了
          }

          },

          messages: { //自定義驗證消息
          "enterprise.enName": {
          required: "請填寫企業名稱!",
          minlength: $.format("至少要{0}個字符!"),
          remote:$.format("該企業名稱已存在!")

          },
          "user.passWord":{
          required:"請填寫確認密碼!",
          rangelength:$.format("密碼要在{0}-{1}個字符之間!")
          },
          passWordConf:{
          required:"請填寫確認密碼!",
          rangelength:$.format("確認密碼要在{0}-{1}個字符之間!"),
          equalTo:"確認密碼要和密碼一致!"
          },

          errorPlacement: function(error, element) { //驗證消息放置的地方
          //error.appendTo( element.parent("td").next("td").children(".msg") );
          error.appendTo( element.parent(".field").next("div"));
          },
          highlight: function(element, errorClass) { //針對驗證的表單設置高亮
          $(element).addClass(errorClass);
          },
          success: function(div) {
          div.addClass("valid");
          }
          });

          });

          自定義方法;

          新建一個js文件:$(document).ready(function(){
          // 字符最小長度驗證(一個中文字符長度為2)
          jQuery.validator.addMethod("stringMinLength", function(value, element, param) {
          var length = value.length;
          for ( var i = 0; i < value.length; i++) {
          if (value.charCodeAt(i) > 127) {
          length++;
          }
          }
          return this.optional(element) || (length >= param);
          }, $.validator.format("長度不能小于{0}!"));

          // 字符最大長度驗證(一個中文字符長度為2)
          jQuery.validator.addMethod("stringMaxLength", function(value, element, param) {
          var length = value.length;
          for ( var i = 0; i < value.length; i++) {
          if (value.charCodeAt(i) > 127) {
          length++;
          }
          }
          return this.optional(element) || (length <= param);
          }, $.validator.format("長度不能大于{0}!"));

          // 字符驗證
          jQuery.validator.addMethod("stringCheck", function(value, element) {
          return this.optional(element) || /^[\u0391-\uFFE5\w]+$/.test(value);
          }, "只能包括中文字、英文字母、數字和下劃線");

          // 中文字兩個字節
          jQuery.validator.addMethod("byteRangeLength", function(value, element, param) {
          var length = value.length;
          for(var i = 0; i < value.length; i++){
          if(value.charCodeAt(i) > 127){
          length++;
          }
          }
          return this.optional(element) || ( length >= param[0] && length <= param[1] );
          }, "請確保輸入的值在3-15個字節之間(一個中文字算2個字節)");

          // 字符驗證
          jQuery.validator.addMethod("string", function(value, element) {
          return this.optional(element) || /^[\u0391-\uFFE5\w]+$/.test(value);
          }, "不允許包含特殊符號!");
          // 必須以特定字符串開頭驗證
          jQuery.validator.addMethod("begin", function(value, element, param) {
          var begin = new RegExp("^" + param);
          return this.optional(element) || (begin.test(value));
          }, $.validator.format("必須以 {0} 開頭!"));
          // 驗證兩次輸入值是否不相同
          jQuery.validator.addMethod("notEqualTo", function(value, element, param) {
          return value != $(param).val();
          }, $.validator.format("兩次輸入不能相同!"));
          // 驗證值不允許與特定值等于
          jQuery.validator.addMethod("notEqual", function(value, element, param) {
          return value != param;
          }, $.validator.format("輸入值不允許為{0}!"));

          // 驗證值必須大于特定值(不能等于)
          jQuery.validator.addMethod("gt", function(value, element, param) {
          return value > param;
          }, $.validator.format("輸入值必須大于{0}!"));

          // 驗證值小數位數不能超過兩位
          jQuery.validator.addMethod("decimal", function(value, element) {
          var decimal = /^-?\d+(\.\d{1,2})?$/;
          return this.optional(element) || (decimal.test(value));
          }, $.validator.format("小數位數不能超過兩位!"));
          //字母數字
          jQuery.validator.addMethod("alnum", function(value, element) {
          return this.optional(element) || /^[a-zA-Z0-9]+$/.test(value);
          }, "只能包括英文字母和數字");
          // 漢字
          jQuery.validator.addMethod("chcharacter", function(value, element) {
          var tel = /^[\u4e00-\u9fa5]+$/;
          return this.optional(element) || (tel.test(value));
          }, "請輸入漢字");
          // 身份證號碼驗證
          jQuery.validator.addMethod("isIdCardNo", function(value, element) {
          return this.optional(element) || /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$/.test(value)||/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[A-Z])$/.test(value);
          }, "請正確輸入您的身份證號碼");

          // 手機號碼驗證
          jQuery.validator.addMethod("isMobile", function(value, element) {
          var length = value.length;
          var mobile = /^(((13[0-9]{1})|(15[0-9]{1}))+\d{8})$/;
          return this.optional(element) || (length == 11 && mobile.test(value));
          }, "請tb正確填寫您的手機號碼");

          // 電話號碼驗證
          jQuery.validator.addMethod("isTel", function(value, element) {
          var tel = /^\d{3,4}-?\d{7,9}$/;    //電話號碼格式010-12345678
          return this.optional(element) || (tel.test(value));
          }, "請正確填寫您的電話號碼");

          // 聯系電話(手機/電話皆可)驗證
          jQuery.validator.addMethod("isPhone", function(value,element) {
          var length = value.length;
          var mobile = /^(((13[0-9]{1})|(15[0-9]{1}))+\d{8})$/;
          var tel = /^\d{3,4}-?\d{7,9}$/;
          return this.optional(element) || (tel.test(value) || mobile.test(value));

          }, "請正確填寫您的聯系電話");

          // 郵政編碼驗證
          jQuery.validator.addMethod("isZipCode", function(value, element) {
          var tel = /^[0-9]{6}$/;
          return this.optional(element) || (tel.test(value));
          }, "請正確填寫您的郵政編碼");

          });

          該文件要先被引用再對form進行驗證。

          注意:remote 中的url 為servlet,但是這個servlet該怎么寫呢

          一開始以為是跟平時的一樣:out.println("用戶名"+name+"已存在!");

          雖然可以驗證,但是還是存在問題:輸入個不存在的name還是提示存在。

          后來還是Google,看到別人也是犯了這樣的錯誤,解決方法時返回true,false.

          但是 doGet 是void類型的,return true 是行不通的。

          后來又請教群里的高手,正確寫法是out.println("true");就可以了。

          哎,費了老長時間

          總算是把問題給解決了。

          posted @ 2012-08-15 15:02 chen11-1| 編輯 收藏

          jQuery mouseover mouseout事件在IE下閃爍的解決方法

          $("#category ul").find("li").each(
              function() {
                  $(this).mouseover(
                      function() {
                          $("#" + this.id + "_menu").show();
                          $(this).addClass("a");
                      }
                  );
                  $(this).mouseout(
                      function() {
                          $(this).removeClass("a");
                          $("#" + this.id + "_menu").hide();
                      }
                  );
              }
          );

          瀏覽器之間的不兼容一直令前端開發者的頭疼,而 IE 更是噩夢。鼠標在下拉菜單移動時菜單會不斷閃爍,tb說明不斷觸發了 mouseover 和 mouseout 事件。

          這貌似涉及到所謂的“事件冒泡”,我不懂 JavaScript,就不在誤人子弟了,詳情請自己 Google,這里只給出解決方法:將 mouseover 改成 mouseentermouseout 改成 mouseleave

          $("#category ul").find("li").each(
              function() {
                  $(this).mouseenter(
                      function() {
                          $("#" + this.id + "_menu").show();
                          $(this).addClass("a");
                      }
                  );
                  $(this).mouseleave(
                      function() {
                          $(this).removeClass("a");
                          $("#" + this.id + "_menu").hide();
                      }
                  );
              }
          );

          最后指出一點,mouseenter 和 mouseleave 事件是 jQuery 庫中實現的,似乎(再次聲明我不懂 JavaScript,所以這里用“似乎”)并不是瀏覽器的原生事件,所以如果你想自己寫 JavaScript 實現的話,請自行 Google,或者查看 jQuery 源碼,如果你能看懂的話。

          參考鏈接:JQuery HowTo: Problems with jQuery mouseover / mouseout events

          轉自:http://demon.tw/programming/jquery-mouseover-mouseout.html

          posted @ 2012-08-15 15:01 chen11-1| 編輯 收藏

          僅列出標題
          共20頁: First 上一頁 5 6 7 8 9 10 11 12 13 下一頁 Last 
          主站蜘蛛池模板: 乐山市| 郎溪县| 龙岩市| 潞西市| 渑池县| 白玉县| 杂多县| 陕西省| 葫芦岛市| 若羌县| 绥芬河市| 肇庆市| 贺州市| 措勤县| 莎车县| 宝鸡市| 外汇| 聂拉木县| 资兴市| 连江县| 五原县| 祁连县| 梧州市| 铁力市| 洛浦县| 湖口县| 焉耆| 搜索| 龙里县| 安新县| 恩平市| 宜兰市| 木兰县| 阳春市| 昔阳县| 乾安县| 蒙阴县| 资中县| 崇州市| 台北县| 通化县|