728x90

얼마전에 고객사에 Informix 12.10.FC14버전을 설치했었는데 기존에 실행했던 쉘스크립트가 실행이 안되더군요. 오늘 IBM My Notifications 메일을 보고 관련된 내용을 알게 되어 공유하고자 합니다.

관련된 문서는 아래 링크에서 확인하실 수 있습니다.

www.ibm.com/support/pages/when-invoking-dbinfodbspacepartnum-error-727-raised

DBINFO 함수를 호출할 때 발생하는 문제인데요. partnum 값이 작은 경우 727 오류가 발생합니다.

$ echo "select first 1 dbinfo('dbspace',partnum) from systabnames;" | dbaccess sysmaster
Database selected.
  727: Invalid or NULL TBLspace number given to dbinfo(dbspace).
Error in line 1
Near character position 56
Database closed.

이전까지는 partnum이 가장 작은 값은 1048577이었지만 12.10.xC14 버전부터는 pseudo-tables, 소위 의사 테이블이 몇가지 추가되었다고 합니다. 14버전은 14.10.xC2 부터라는군요. 아래처럼 partnum 값이 6부터 153 까지 몇개 추가되었음을 알 수 있습니다.

$ echo "select first 10 partnum from sysmaster:systabnames;" | dbaccess stores_demo
Database selected.
    partnum
          6
         10
         15
         89
        153
    1048577
    1048578
    1048579
    1048580
    1048582

따라서 DBINFO 사용시 오류를 회피하기 위해서는 partnum 값이 1048576 이상인 값을 대상으로 조회해야 오류가 발생하지 않는다고 합니다. 관리적인 목적으로 DBINFO 함수를 사용하고 있다면 조건을 추가해야겠네요. 제가 테스트한바로는 위에서 보이는 153 이상의 조건으로도 오류가 발생하지는 않지만 IBM에서 권고하는 방법을 사용하는게 좋겠죠.

IBM문서에는 DBINFO_DBSPACE_RETURN_NULL_FOR_INVALID_PARTNUM 환경변수를 설정하면 된다고 합니다만 설정 전후 동작에 차이가 없는 것 같습니다. IBM에 별도의 패치버전을 요청해야되나 봅니다.

$ export DBINFO_DBSPACE_RETURN_NULL_FOR_INVALID_PARTNUM=1
$ echo "select first 1 dbinfo('dbspace',partnum) from systabnames;" | dbaccess sysmaster
Database selected.
  727: Invalid or NULL TBLspace number given to dbinfo(dbspace).
Error in line 1
Near character position 56
Database closed.
$ dbaccess sysmaster -
Database selected.
> set environment DBINFO_DBSPACE_RETURN_NULL_FOR_INVALID_PARTNUM "1";
19840: Invalid session environment variable.
Error in line 1
Near character position 65
>

12.10.xC14 버전 이상을 사용하실 때 참고하시면 좋겠습니다.

728x90
728x90

오늘은 IBM Community에서 인포믹스 Smart Trigger 구현중에 발생한 오류에 대해서 질문이 있었습니다. 인포믹스 12.10.xC9 버전부터 Smart Trigger라는 기능이 소개되었는데 IBM Knowledge Center에서의 설명은 아래와 같습니다.

In a relational database environment, client applications are constantly monitoring and triggering other complex jobs, based on changes happening in the database. Applications need to be able to detect events in the database as they happen, without adding overhead to the database server.
With the release of Informix 12.10.xC9, clients can now create JDBC Smart Triggers to register changes in a dataset, using SELECT statements and WHERE clauses, and push data from the server to the client. Scaling is achieved by clients not having to poll for data, while the database server's parallel architecture can feed the data to all clients by asynchronously reading logical log file changes. This design lets client applications scale linearly without adding significant overhead to the database server or any OLTP applications making changes to the database.

요약하면 스마트 트리거를 사용하면 데이터베이스 서버에 변경을 가하지 않고 클라이언트 프로그램에서 정의한 SELECT 문장의 조건으로 데이터베이스 데이터의 변경을 감지할 수 있다고 설명하고 있습니다. 데이터베이스의 트리거와는 달리 비동기식으로 작동하므로 데이터베이스에 가해지는 부하가 적다고 합니다.

 

테스트를 위해 HCL 커뮤니티의 포스트에서 Java 코드를 참고했습니다.

http://www.hcl-informix-user.com/blogs/introducing-hcl-informix-smart-triggers

 

Java 프로그램을 실행하기 전에 데이터를 입력할 테이블을 하나 만듭니다.

CREATE TABLE account (id integer primary key, name varchar(200), balance float);

코드 내용에서 JDBC url 내용을 수정합니다. sysadmin 데이터베이스와 모니터링할 데이터베이스의 로케일을 고려하여 DB_LOCALE과 CLIENT_LOCALE 설정값을 지정합니다. 이 예시의 경우 sysadmin은 en_us.819, bank는 en_us.utf8입니다.

import java.sql.SQLException;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.informix.smartTrigger.IfmxSmartTriggerCallback;
import com.informix.smartTrigger.IfxSmartTrigger;
public class SmartTrigger implements IfmxSmartTriggerCallback {
               private final JsonParser p = new JsonParser();
               public static void main(String[] args) throws SQLException {
                              try(IfxSmartTrigger trigger = new IfxSmartTrigger("jdbc:informix-sqli://xxx.xx.xx.xx:53331/sysadmin:user=informix;password=password;DB_LOCALE=en_us.utf8;CLIENT_LOCALE=en_us.utf8");) {
                                             trigger.label("bank_alert").timeout(5); // optional parameters
                                             trigger.addTrigger("account", "informix", "bank", "SELECT * FROM account WHERE balance < 0", new SmartTrigger());
                                             trigger.watch();
                              }
               }
               @Override
               public void notify(String jsonString) {
                              JsonObject json = p.parse(jsonString).getAsJsonObject();
                              System.out.println("Bank Account Ping!");
                              if (json.has("ifx_isTimeout")) {
                                             System.out.println("-- No balance issues");
                              } else {
                                             System.out.println("-- Bank Account Alert detected!");
                                             System.out.println("   " + json);
                              }
               }
}

코드 내용을 보면 GSON 라이브러리를 사용하고 있으므로 다운로드 받습니다. 2.8.6 버전을 받아서 컴파일해보니 오류가 발생해서 2.8.2 버전을 다시 받았습니다.

[informix@db2 skjeong]$ wget https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.2/gson-2.8.2.jar
--2020-04-23 11:17:35--  https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.2/gson-2.8.2.jar
Resolving repo1.maven.org (repo1.maven.org)... 151.101.196.209
Connecting to repo1.maven.org (repo1.maven.org)|151.101.196.209|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 232932 (227K) [application/java-archive]
Saving to: ‘gson-2.8.2.jar’
100%[===================================================================================================================================================>] 232,932      366KB/s   in 0.6s
2020-04-23 11:17:36 (366 KB/s) - ‘gson-2.8.2.jar’ saved [232932/232932]

아래는 Java 코드 컴파일 후 프로그램을 실행한 화면입니다. 저 같은 경우 서버에 java 실행파일들이 여기저기 흩어져있어서 되는 것으로 일단 사용했습니다. 1.8 이상의 JRE와 인포믹스 JDBC 드라이버는 4.10.xC9 이상을 사용하시면 됩니다.

실행하면 timeout 값(초) 간격으로 'Bank Account Ping!' 메시지가 출력됩니다. 

[informix@db2 skjeong]$ export CLASSPATH=/work1/informix/1210FC10/jdbc/lib/ifxjdbc.jar:/work1/informix/ids1410fc3/skjeong/gson-2.8.2.jar:.
[informix@db2 skjeong]$ /opt/ibm/db2/V11.5.dc/java/jdk64/bin/javac SmartTrigger.java
[informix@db2 skjeong]$ /work1/informix/ids1410fc3/jvm/jre/bin/java SmartTrigger
Bank Account Ping!
-- No balance issues
Bank Account Ping!
-- No balance issues

이제 프로그램에서 정의한 조건에 감지될 수 있는 INSERT와 DELETE문장을 실행해보겠습니다.

[informix@db2 skjeong]$ dbaccess bank -
Database selected.
> insert into account (id, name, balance) values (22, 'John Doe', -23.45);
1 row(s) inserted.
> delete from account where id = 22;
1 row(s) deleted.

앞서 실행한 Java 프로그램에서 정의한 SELECT 문장(은 balance가 음수일 경우에 경고를 알리는 메시지를 출력하도록 되어 있습니다. (SELECT * FROM account WHERE balance < 0) 출력 데이터 형식은 JSON입니다.

-- Bank Account Alert detected!
   {"operation":"insert","table":"account","owner":"informix","database":"bank","label":"bank_alert_1","txnid":1421639512296,"operation_owner_id":1001,"operation_session_id":584,"commit_time":1587608886,"op_num":1,"restart_logid":331,"restart_logpos":5329128,"rowdata":{"id":22,"name":"John Doe","balance":-23.4499999999999990}}
Bank Account Ping!
-- No balance issues
Bank Account Ping!
-- No balance issues
-- Bank Account Alert detected!
   {"operation":"delete","table":"account","owner":"informix","database":"bank","label":"bank_alert_1","txnid":1421639540968,"operation_owner_id":1001,"operation_session_id":584,"commit_time":1587608955,"op_num":1,"restart_logid":331,"restart_logpos":5357804,"rowdata":{"id":22,"name":"John Doe","balance":-23.4499999999999990}}
Bank Account Ping!
-- No balance issues

 

참고사이트

https://www.ibm.com/support/knowledgecenter/SSGU8G_12.1.0/com.ibm.po.doc/new_features_ce.htm#newxc9__xc9_push_data

https://www.ibm.com/support/knowledgecenter/en/SSGU8G_12.1.0/com.ibm.jdbc_pg.doc/ids_jdbc_st_01.htm

728x90
728x90

안타깝게도 인포믹스 12.10.xC14버전에서 추가로 확인된 defect 정보입니다.

이번에는 CHAR_LENGTH 함수의 문제인데요. 지난번 LPAD/RPAD 함수 사용시 발생하는 오류와 유사합니다.

 

오류가 발생하는 조건은 아래와 같습니다.

1) character set과 연관 없어 보임 (en_us.utf8, ko_kr.ksc, ko_kr.949, ko_kr.ksc인 경우 모두 오류 발생)

2) source string이 empty string('')인 경우

 

사용 빈도에 따라 발생 가능성이 높은 오류입니다. 아래는 오류를 재현한 과정입니다.

/work2/INFORMIX/1210FC14]dbaccess tdb -
Database selected.
> select char_length("") from systables where tabid = 1;
  202: An illegal character has been found in the statement.
Error in line 1
Near character position 52

이 내용은 APAR IT32473: -202 ERROR WHEN USING CHAR_LENGTH("") FOR A NULL VALUE 로 확정되었습니다.

12.10.xC14 Fix Pack 적용은 하지 않는 것이 좋겠네요.

728x90
728x90

인포믹스 12.10.FC14버전에서 발견된 defect를 공유드립니다.

경우에 따라서는 심각한 문제가 될 것 같은데요. LPAD와 RPAD 함수 사용시 발생하는 문제입니다.

 

오류가 발생하는 조건은 아래와 같습니다.

1) multi-byte character set으로 구성된 데이터베이스 (en_us.utf8, ko_kr.ksc, ko_kr.949등)

2) source string이 varchar 또는 lvarchar 타입일 경우

3) source string이 empty string('')인 경우

 

상당히 오류가 발생할 가능성이 높은 조건입니다. 아래는 오류를 재현한 과정입니다.

/work2/INFORMIX/1210FC14]export DB_LOCALE=en_us.utf8
/work2/INFORMIX/1210FC14]export CLIENT_LOCALE=en_us.utf8
/work2/INFORMIX/1210FC14]echo "create database tdb with log"  | dbaccess -
Database created.
Database closed.
/work2/INFORMIX/1210FC14]dbaccess tdb -
Database selected.
> select lpad ( '', 2, '0' ) from sysmaster:sysdual;
  202: An illegal character has been found in the statement.
Error in line 1
Near character position 48
> select rpad ( '', 2, '0' ) from sysmaster:sysdual;
  202: An illegal character has been found in the statement.
Error in line 1
Near character position 48
>

IBM Community에 문의한 결과 이번 문제는 APAR IT32236 LPAD() and RPAD() on empty string getting -202 when used in multi-byte character set database로 확정되었습니다.

 

12.10.xC14 Fix Pack이 공개된지 얼마되지 않았는데 안타깝네요.

기존에는 문제없이 작동하는 기능이었기 때문에 패치적용시 우선적으로 고려해야 할 사항입니다.

 

추가로 확인된 바로는 12.10.xC15에서 수정될 예정입니다. 2020년 2분기에 공개될 예정입니다.

728x90
728x90

안녕하세요. 요즘 IBM 커뮤니티에서 열심히 댓글놀이를 하고 있는데요. 며칠전에 Informix에서 문자열에 대한 최빈값(MODE)을 구하는 방법에 대한 질문글이 올라왔습니다. 최빈값은 통계학에서 쓰는 용어로 액셀이나 분석 솔루션에서 MODE라는 함수로 사용되기도 합니다. 아래는 위키백과의 최빈값에 대한 설명입니다.

 

최빈값(最頻-), 모드(mode)는 통계학 용어로, 가장 많이 관측되는 수, 즉 주어진 값 중에서 가장 자주 나오는 값이다. 예를 들어, {1, 3, 6, 6, 6, 7, 7, 12, 12, 17}의 최빈값은 6이다. 최빈값은 산술 평균과 달리 유일한 값이 아닐 수도 있다.

또한 주어진 자료나 관측치의 값이 모두 다른 경우에는 존재하지 않는다.

주어진 자료에서 평균이나 중앙값을 구하기 어려운 경우에 특히 유용하다.

 

그런데 최빈값이라 함은 숫자가 대상이지 문자열은 아닙니다. 그리고 SQL에서는 MODE라는 함수가 따로 제공되는 것도 아니어서 문자열을 대상으로 하려면 별도의 로직을 구현해야합니다.

질문에서 제시하는 샘플데이터와 원하는 결과세트는 아래와 같습니다.

 

<샘플데이터>

Name dob score
JESSE 1992/10/27 10
JESSE 1992/10/27 20
JESSE 1992/11/06 30
JESSE 1992/11/11 40
JESSICA 1992/03/11 50
JESSICA 1992/11/03 60
JESSICA 1992/10/29 70
JESSICA 1992/11/10 80
JESSICA 1992/11/30 90
JESSICA 1992/11/12 10
JESSICA 1992/12/07 20
JESSICA 1992/12/09 30

 

<결과세트>

Name dob avg(score)
JESSE 1992/12/07  
JESSICA 1992/11/??  

 

결과세트에서 요구하는 사항은 다음과 같습니다.

1) 이름별로 가장 연도와 월 기준으로 가장 많은 값을 찾는다.

2) 일자는 해당 월의 아무 일자나 허용한다.

3) 1에서 찾은 값의 개수가 같은 것이 있으면 연도, 월, 일자를 같은 값을 우선한다.

 

그래서 이리저리 검색을 해서 아래와 같은 쿼리를 만들었습니다.

WITH t1 AS
(
SELECT 'JESSE' Name, '1992/10/27' dob, 10 score 
UNION ALL SELECT 'JESSE', '1992/10/27', 20 
UNION ALL SELECT 'JESSE', '1992/11/06', 30 
UNION ALL SELECT 'JESSE', '1992/11/11', 40 
UNION ALL SELECT 'JESSICA', '1992/03/11', 50 
UNION ALL SELECT 'JESSICA', '1992/11/03', 60 
UNION ALL SELECT 'JESSICA', '1992/10/29', 70 
UNION ALL SELECT 'JESSICA', '1992/11/10', 80 
UNION ALL SELECT 'JESSICA', '1992/11/30', 90 
UNION ALL SELECT 'JESSICA', '1992/11/12', 10 
UNION ALL SELECT 'JESSICA', '1992/12/07', 20  
UNION ALL SELECT 'JESSICA', '1992/12/09', 30 
)
SELECT a.Name,
       a.dob,
       a.avg	  
  FROM (SELECT t1.Name, 
               t1.dob, 
               ROW_NUMBER() OVER (PARTITION BY t1.Name ORDER BY COUNT(*) DESC) rn, 
               AVG(t1.score) OVER (PARTITION BY t1.Name) avg
          FROM t1,
               (SELECT t1.Name, 
                       t1.dob[1,7], 
                       RANK() OVER (PARTITION BY t1.Name ORDER BY COUNT(*) DESC) rk
                  FROM t1
                 GROUP BY t1.Name, t1.dob[1,7]
               ) t2
         WHERE t2.rk = 1
           AND t1.Name = t2.Name
           AND t1.dob like t2.dob||'%'
         GROUP BY t1.Name, t1.dob, t1.score
       ) a
 WHERE rn =1

쿼리의 흐름은 다음과 같습니다.

1) 이름을 기준으로 연도,월별 개수가 가장 많은 것을 구합니다. 가장 많은 개수가 같을 경우를 고려해 RANK 함수를 사용합니다. 그러면 같은 랭킹인 경우는 모두 첫번째가 됩니다.

2) 1에서 구한 데이터를 기준으로 일자를 포함하여 개수가 가장 많은 것을 구합니다. 여기선 월별로 일자 하나만 선택해야하므로 ROW_NUMBER를 사용합니다.

 

아래는 실행한 결과입니다.

[informix@db2 skjeong]$ dbaccess stores_demo mode.sql
Database selected.
name    dob                     avg
JESSE   1992/10/27 25.0000000000000
JESSICA 1992/11/30 60.0000000000000
2 row(s) retrieved.

 

인포믹스에서의 예제이긴 하지만 대부분의 RDBMS에서 지원하는 함수이기 때문에 필요한 경우 적용하기는 어렵지 않으실겁니다. 혹시 이 글을 읽는 분들께서 더 나은 방법을 알고 계시다면 조언 부탁드리겠습니다.

 

제가 참고한 사이트는 아래와 같습니다.

https://www.mssqltips.com/sqlservertip/3543/calculate-the-statistical-mode-in-sql-server-using-tsql/

 

 

데이터베이스 사랑넷에 자문을 구해 쿼리를 수정해보고, 새로운 쿼리도 알게 됐습니다.

위의 요구사항보다 조건을 좀 더 구체적으로 설정했습니다.

 

1) 평균은 월평균이 되어야한다. 이전 것은 이름만 기준으로한 평균

2) 가장 많은 갯수가 동일할 경우의 우선순위는? (빠른 날짜, 느린 날짜, 낮은 평균, 높은 평균 등)

여기서는 빠른 날짜를 기준으로 합니다.

 

아래는 수정된 쿼리입니다. 제가 수정한 쿼리는 마농님의 조언에 따라 약간 수정한 것입니다.

테스트를 위해 WITH절에  샘플 레코드를 추가했습니다.

--- 제가 수정한 쿼리
WITH t1 AS
(
SELECT 'JESSE' Name , '1992/08/06' dob, 30 score
UNION ALL SELECT 'JESSE', '1992/08/06', 40 
UNION ALL SELECT 'JESSE', '1992/07/27', 10
UNION ALL SELECT 'JESSE', '1992/07/27', 20 
UNION ALL SELECT 'JESSE', '1992/11/06', 30 
UNION ALL SELECT 'JESSE', '1992/11/11', 40 
UNION ALL SELECT 'JESSICA', '1992/03/11', 50 
UNION ALL SELECT 'JESSICA', '1992/11/03', 60 
UNION ALL SELECT 'JESSICA', '1992/10/29', 70 
UNION ALL SELECT 'JESSICA', '1992/11/10', 80 
UNION ALL SELECT 'JESSICA', '1992/11/30', 90 
UNION ALL SELECT 'JESSICA', '1992/11/12', 10 
UNION ALL SELECT 'JESSICA', '1992/12/07', 20  
UNION ALL SELECT 'JESSICA', '1992/12/09', 30 
)
SELECT a.Name,
       a.dob,
       a.avg	  
  FROM (SELECT t1.Name, 
               t1.dob, 
               ROW_NUMBER() OVER (PARTITION BY t1.Name ORDER BY COUNT(*) DESC, t1.dob ASC) rn, 
               AVG(t1.score) OVER (PARTITION BY t1.Name, t1.dob[1,7] ) avg
          FROM t1,
               (SELECT t1.Name, 
                       t1.dob[1,7], 
                       RANK() OVER (PARTITION BY t1.Name ORDER BY COUNT(*) DESC) rk
                  FROM t1
                 GROUP BY t1.Name, t1.dob[1,7]
               ) t2
         WHERE t2.rk = 1
           AND t1.Name = t2.Name
           AND t1.dob like t2.dob||'%'
         GROUP BY t1.Name, t1.dob, t1.score
       ) a
 WHERE rn =1
--- 마농님의 쿼리 (WITH문 생략)
SELECT *
  FROM (SELECT name
             , dob
             , avg_m
             , ROW_NUMBER() OVER(
               PARTITION BY name ORDER BY cnt_m DESC, cnt_d DESC, dob) rn
          FROM (SELECT name
                     , dob
                     , COUNT(*)   OVER(PARTITION BY name, dob[1,7]) cnt_m
                     , COUNT(*)   OVER(PARTITION BY name, dob     ) cnt_d
                     , AVG(score) OVER(PARTITION BY name, dob[1,7]) avg_m
                  FROM t1
                ) a
        ) a
 WHERE rn = 1
;

제가 올린 질문글은 아래 링크에서 참고해주세요.

http://database.sarang.net/?inc=read&aid=3484&criteria=informix&subcrit=qna&id=&limit=20&keyword=&page=1

728x90
728x90

index page 최대 개수에 대해 조사하다보니 extent 할당에 대해서도 우연히 문서를 읽게 되었습니다.

IBM Knowledge Center에 따르면 11.70.xC1 버전부터 partition header pages의 공간이 부족해지면 secondary header pages가 자동으로 할당된다고 합니다.

https://www.ibm.com/support/knowledgecenter/SSGU8G_11.70.0/com.ibm.perf.doc/ids_prf_309.htm

If you have a table that needs more extents and the database server runs out of space on the
partition header page, the database server automatically allocates extended secondary partition
header pages to accommodate new extent entries.
The database server can allocate up to 32767 extents for any partition, unless the size of a table
dictates a limit to the number of extents.

따라서 11.70 버전부터 extent가 최대 32,767개 까지 할당됩니다. 관리할 점은 줄었네요.

그렇지만 성능을 고려한다면 개수를 적게 유지하는 것이 좋겠죠.

 

아래와 같이 데이터를 대량으로 입력해서 extent 개수를 많이 늘려보았습니다.

일반적으로는 EXTENT DOUBLING 규칙에 의해 extent 크기가 2배씩 커지지만 작은 페이지 크기로 일정하게 할당되도록 NO_EXTENT_DOUBLING 옵션을 활성화 했습니다.

참고로 NO_EXTENT_DOUBLING 옵션은 11.70.xC9부터 사용가능합니다.

drop table "informix".log_01;
create table "informix".log_01
  (
    col1 varchar(50),
    col2 varchar(32),
    col3 varchar(5),
    col4 varchar(5),
    col5 varchar(10)
  ) in dbs1 extent size 16 next size 16 lock mode page;
  ...

아래의 SQL문장으로 1천만건의 레코드를 입력합니다.

$ nohup dbaccess -e demo /informix/skjeong/insert1.sql > /informix/skjeong/insert1.log 2>&1 &
$ cat insert1.sql
insert into log_01
select 'dolore eu fugiat nulla pariatur. Excepteur sint oc',
       '180e70d7-8684-4674-8d42-3c1e5f3b',
       'labor',
       'eiusm',
       level
from sysmaster:sysdual
connect by level <= 10000000;

데이터 입력중에 oncheck 명령으로 테이블의 extent 수를 확인해보았습니다.

와우! 2356개입니다. EXTENT DOUBLING이 되고 한계가 3만2천개라면 거의 제한이 없는 것으로 봐도 되겠지요.

TBLspace Report for demo:informix.log_01
    Physical Address               2:5
    Creation date                  02/17/2020 13:23:41
    TBLspace Flags                 901        Page Locking
                                              TBLspace contains VARCHARS
                                              TBLspace use 4 bit bit-maps
    Maximum row size               107
    Number of special columns      5
    Number of keys                 0
    Number of extents              2356
    Current serial value           1
    Current SERIAL8 value          1
    Current BIGSERIAL value        1
    Current REFID value            1
    Pagesize (k)                   2
    First extent size              8
    Next extent size               128
    Number of pages allocated      301056
    Number of pages used           301056
    Number of data pages           300981
    Number of rows                 5422921
    Partition partnum              2097154
    Partition lockid               2097154
    Extents
         Logical Page     Physical Page        Size Physical Pages
                    0         6:5000427           8          8
                    8         6:5000483           8          8
                   16         6:5000611          16         16
                   32         6:5000851          32         32
                   64         6:5001395          64         64
                  128         6:5002675         128        128
                  256         6:5004083         128        128
                  384         6:5005363         128        128
                  512         6:5006515         128        128
                  ...
728x90
728x90

안녕하세요. IBM Community에서 Informix의 rowid를 참조하는 내용이 있어 공유하고자 합니다.

원래 글의 내용은 Informix page 할당 개수의 한계에 관련된 질문이었는데 파티션된 테이블의 rowid에 대한 내용이 중간에 언급되었습니다.

인포믹스의 파티션된 테이블은 rowid 컬럼이 존재하지 않는데, 파티션 테이블에 rowid를 표시되도록 하려면 아래의 명령으로 숨겨진 ROWID 컬럼을 추가할 수 있습니다.

ALTER TABLE frag1 ADD ROWIDS;


그런데 ifx_row_id라는 숨겨진 컬럼이 있다고 합니다. 이리저리 자료들을 찾아보니 11.50 버전부터 지원되었다고 하는데요. IBM에서 공식적으로 문서화되지 않았습니다.

기존 테이블에 rowid 컬럼을 추가하지 않고도 rowid를 대체하여 사용할 수 있습니다.

보여지는 형식은 <partnum>:<rowid> 입니다.

특징으로는 아래와 같이 SEQUENTIAL SCAN이 발생한다는 점입니다.

QUERY: (OPTIMIZATION TIMESTAMP: 01-02-2020 17:27:54)
------
select ifx_row_id from systables where ifx_row_id='1048900:1301'
Estimated Cost: 7
Estimated # of Rows Returned: 1
  1) informix.systables: SEQUENTIAL SCAN
        Filters: informix.systables.ROWID = '1048900:1301'


반면에 ROWID 컬럼은 INDEX SCAN을 합니다.

QUERY: (OPTIMIZATION TIMESTAMP: 01-02-2020 17:51:25)
------
select * from systables where rowid=2058
Estimated Cost: 1
Estimated # of Rows Returned: 1
  1) informix.systables: INDEX PATH
    (1) Index Name: (ROWID)
        Index Keys: ROWID
        Lower Index Filter: informix.systables.ROWID = 2058

ifx_row_id 컬럼은 일반적인 사용자 업무에 사용되기보다는 마이그레이션등의 작업에 이용할 수 있는 옵션이 될 수 있을 것 같습니다.


아래 APAR를 보면 WITH ROWIDS 옵션을 쓰기보다 일반 컬럼을 primary key로 사용할 것을 권고하고 있습니다.

IC94738: IFX_ROW_ID UNDOCUMENTED FEATURE IS DOING SEQUENTIAL SCAN INSTEAD OF READING DIRECTLY IN THE APPROPRIATE PAGE

Using the WITH ROWIDS Option
Nonfragmented tables contain a hidden column called rowid, but
by default, fragmented tables have no rowid column. You can use
the WITH ROWIDS keywords to add the rowid column to a fragmented
table. Each row is automatically assigned a unique rowid value
that remains stable for the life of the row and that the
database server can use to find the physical location of the
row. Each row requires an additional four bytes to store the
rowid.
Important: This is a deprecated feature. Use primary keys as an
access method rather than the rowid column.

https://www-01.ibm.com/support/docview.wss?uid=swg1IC94738

728x90
728x90

안녕하세요. IBM Informix 12.10.xC10 버전부터 기본(Primary)/미러(Mirror) 청크(Chunk)를 교체하는 기능이 생겨 테스트를 해봤습니다.


제가 미러 청크를 만든 방법과 교체한 내용을 소개해 드리겠습니다.


1. onCONFIG 옵션 변경

미러 청크를 사용하려면 onCONFIG의 MIRROR 옵션을 1로 변경해야 합니다.

그리고 처음 미러 청크를 만드는 경우라면 MIRRORPATH는 공란으로 두어야 합니다.

MIRRORPATH는 root dbspace에 대한 청크 경로이므로 공란으로 두지 않으면 Informix 인스턴스가 시작되지 않습니다.


2. 기존의 청크에 미러 청크 생성하기

미러 청크를 생성하는 것은 onspaces 명령이나 sysadmin api를 통해 가능한데 여기서는 onspaces 명령으로 해보겠습니다.


먼저 기본 청크 경로를 확인합니다.


$ onstat -d


IBM Informix Dynamic Server Version 12.10.FC12W1WE -- on-Line -- Up 00:01:25 -- 227552 Kbytes


Dbspaces

address          number   flags      fchunk   nchunks  pgsize   flags    owner    name

700000020476028  1        0x4000001  1        2        4096     N  BA    informix rootdbs

7000000205abbe0  2        0x5000001  2        1        4096     N PBA    informix plog

700000020476dc8  3        0x4000001  3        1        4096     N  BA    informix llog

700000020477bf0  4        0x4000001  4        1        4096     N  BA    informix datadbs1

70000002058f850  5        0x4000001  5        1        4096     N  BA    informix datadbs2

70000002058fa90  6        0x4000001  6        1        4096     N  BA    informix datadbs3

70000002058fcd0  7        0x4000001  7        1        8192     N  BA    informix data8dbs1

700000022733028  8        0x4000001  8        1        8192     N  BA    informix data8dbs2

700000022733268  9        0x4000001  9        1        8192     N  BA    informix data8dbs3

7000000227334a8  10       0x2001     10       1        8192     N TBA    informix tmpdbspace

7000000227336e8  11       0x4008001  11       1        4096     N SBA    informix sbspace1

700000022733928  12       0xa001     12       1        4096     N UBA    informix tmpsbspace

 12 active, 2047 maximum


Chunks

address          chunk/dbs     offset     size       free       bpages     flags pathname

700000020476268  1      1      0          38912      5453                  PO-B-D /opt/IBM/informix/storage/rootdbs

700000022735028  2      2      0          16384      0                     PO-BED /opt/IBM/informix/storage/ol_informix1210_4_plog_p_1

700000022736028  3      3      0          151426     1373                  PO-BED /opt/IBM/informix/storage/ol_informix1210_4_llog_p_1

700000022737028  4      4      0          16384      15145                 PO-BED /opt/IBM/informix/storage/ol_informix1210_4_datadbs1_p_1

700000022738028  5      5      0          16384      16331                 PO-BED /opt/IBM/informix/storage/ol_informix1210_4_datadbs2_p_1

700000022739028  6      6      0          16384      16331                 PO-BED /opt/IBM/informix/storage/ol_informix1210_4_datadbs3_p_1

70000002273a028  7      7      0          8192       8139                  PO-BED /opt/IBM/informix/storage/ol_informix1210_4_data8dbs1_p_1

70000002273b028  8      8      0          8192       8139                  PO-BED /opt/IBM/informix/storage/ol_informix1210_4_data8dbs2_p_1

70000002273c028  9      9      0          8192       8139                  PO-BED /opt/IBM/informix/storage/ol_informix1210_4_data8dbs3_p_1

70000002273d028  10     10     0          9216       9163                  PO-BE- /opt/IBM/informix/storage/ol_informix1210_4_tmpdbspace_p_1

70000002273e028  11     11     0          16384      11822      11879      POSB-D /opt/IBM/informix/storage/ol_informix1210_4_sbspace1_p_1

                                 Metadata 868        4138       868

70000002273f028  12     12     0          16384      11879      11879      POSB-- /opt/IBM/informix/storage/ol_informix1210_4_tmpsbspace_p_1

                                 Metadata 868        4138       868

700000022734028  13     1      0          16384      11097                 PO-BED /opt/IBM/informix/storage/ol_informix1210_4_rootdbs_p_1

 13 active, 32766 maximum


NOTE: The values in the "size" and "free" columns for DBspace chunks are

      displayed in terms of "pgsize" of the DBspace to which they belong.



Expanded chunk capacity mode: always



여기 예에서는 datadbs1 dbspace의 청크에 미러 청크를 생성해보겠습니다.


$ onspaces -m datadbs1 -p /opt/IBM/informix/storage/ol_informix1210_4_datadbs1_p_1 -o 0 -m /opt/IBM/informix/storage/ol_informix1210_4_datadbs1_p_1_mirror 0


WARNING: Turning mirror on for 'datadbs1'.


Do you really want to continue? (y/n)y

Verifying physical disk space, please wait ...

The Space "datadbs1" is now mirrored.


명령을 실행하면 미러 청크를 만들것인지 확인하는 메시지가 나옵니다.

여기서 'y' 를 입력하고 엔터를 누르면 미러 청크가 생성됩니다.


3. 생성한 미러 청크 확인

onstat -d 명령으로 미러 청크가 생성되었는지 확인합니다.

미러 청크의 경우 flags 값의 맨 처음 값이 M으로 표시됩니다.


$ onstat -d

...

Chunks

address          chunk/dbs     offset     size       free       bpages     flags pathname

700000020476268  1      1      0          38912      5453                  PO-B-D /opt/IBM/informix/storage/rootdbs

700000022735028  2      2      0          16384      0                     PO-BED /opt/IBM/informix/storage/ol_informix1210_4_plog_p_1

700000022736028  3      3      0          151426     1373                  PO-BED /opt/IBM/informix/storage/ol_informix1210_4_llog_p_1

700000022737028  4      4      0          16384      15145                 PO-B-D /opt/IBM/informix/storage/ol_informix1210_4_datadbs1_p_1

700000022e2e028  4      4      0          16384      0                     MO-B-D /opt/IBM/informix/storage/ol_informix1210_4_datadbs1_p_1_mirror



onstat -m 명령으로 로그 메시지를 확인해보면 아래와 같이 나옵니다.


$ onstat -m


IBM Informix Dynamic Server Version 12.10.FC12W1WE -- on-Line -- Up 00:03:19 -- 227552 Kbytes


Message Log File: /opt/IBM/informix/ol_informix1210_4.log

11:33:05  Checkpoint Statistics - Avg. Txn Block Time 0.000, # Txns blocked 0, Plog used 18, Llog used 2


11:33:06  Checkpoint Completed:  duration was 0 seconds.

11:33:06  Thu Apr 11 - loguniq 808, logpos 0x3b94050, timestamp: 0x69dc6db Interval: 284


11:33:06  Maximum server connections 0

11:33:06  Checkpoint Statistics - Avg. Txn Block Time 0.000, # Txns blocked 1, Plog used 0, Llog used 3


11:33:06  The Space "datadbs1" is now mirrored.


11:33:06  Space 'datadbs1' -- Recovery Begins(700000020552ec8)

11:33:06  Chunk Number 4 - '/opt/IBM/informix/storage/ol_informix1210_4_datadbs1_p_1_mirror' -- Recovery Begins(700000020552ec8)

11:33:23  Chunk Number 4 - '/opt/IBM/informix/storage/ol_informix1210_4_datadbs1_p_1_mirror' -- online

11:33:23  Checkpoint Completed:  duration was 0 seconds.

11:33:23  Thu Apr 11 - loguniq 808, logpos 0x3b97018, timestamp: 0x69dc6e8 Interval: 285


11:33:23  Maximum server connections 0

11:33:23  Checkpoint Statistics - Avg. Txn Block Time 0.000, # Txns blocked 0, Plog used 0, Llog used 3


11:33:23  Space 'datadbs1' -- Recovery Complete(700000020552ec8)


Recovery Complete 메시지가 보이는 순간부터 미러링(Mirroring)이 시작됩니다.



4. 기본 청크와 미러 청크 교체하기

기본 청크와 미러 청크를 교체하려면 sysadmin의 task function의 swap_mirror 명령을 사용합니다.


$ dbaccess sysadmin -


Database selected.


> execute function task('modify chunk swap_mirror',4);




(expression)  Primary/mirror swap for chunk 4 succeeded.


1 row(s) retrieved.



5. 기본 청크와 미러 청크가 교체되었는지 확인

onstat -d 명령으로 기본 청크와 미러 청크가 교체되었는지 확인합니다.


$ onstat -d


...

Chunks

address          chunk/dbs     offset     size       free       bpages     flags pathname

700000020476268  1      1      0          38912      5453                  PO-B-D /opt/IBM/informix/storage/rootdbs

700000022735028  2      2      0          16384      0                     PO-BED /opt/IBM/informix/storage/ol_informix1210_4_plog_p_1

700000022736028  3      3      0          151426     1373                  PO-BED /opt/IBM/informix/storage/ol_informix1210_4_llog_p_1

700000022737028  4      4      0          16384      15145                 PO-B-D /opt/IBM/informix/storage/ol_informix1210_4_datadbs1_p_1_mirror

700000022e2e028  4      4      0          16384      0                     MO-B-D /opt/IBM/informix/storage/ol_informix1210_4_datadbs1_p_1



onstat -m 명령으로 로그 메시지를 확인해보면 아래와 같이 나옵니다.


$ onstat -m


...

11:36:36  Primary/mirror swap for chunk 4 succeeded.

11:36:36  Checkpoint Completed:  duration was 1 seconds.

11:36:36  Thu Apr 11 - loguniq 808, logpos 0x3b9a07c, timestamp: 0x69dc70c Interval: 286


11:36:36  Maximum server connections 1

11:36:36  Checkpoint Statistics - Avg. Txn Block Time 0.000, # Txns blocked 0, Plog used 6, Llog used 3


미러링은 일반적으로 디스크 오류가 발생했을 때 데이터베이스 서버를 온라인에서 복구하기 위한 기능이지만,

swap_mirror 명령이 추가됨으로써 인스턴스가 온라인인 상태에서 파일을 교체할 수 있어, 스토리지 위치를 변경할 때 유용하게 사용할 수 있을 것 같습니다.


728x90
728x90

안녕하세요. 인포믹스 12.10.FC12, 12.10.FC12W1, 14.10.FC1 버전에서 발생하는 문제를 소개드립니다.


문제가 발생한 이후부터는 인포믹스 프로세스가 시작되지 않으므로 매우 치명적인 결함입니다.


문제가 발생할 수 있는 조건은 아래와 같습니다.

1. 해당 테이블에 VARCHAR 컬럼을 추가한다.

2. 추가한 VARCHAR 컬럼의 사이즈를 축소한다.


위와 같은 상황에서 UPDATE 문장을 실행하면 오류가 발생하면서 인포믹스 프로세스가 다운됩니다.

그러나 항상 다운되는 것은 아니고 대상 테이블에 저장된 데이터 길이에 따라 다운될 수도, 다운되지 않을 수도 있습니다.

아래는 인포믹스 12.10.FC12와 14.10.FC1 버전의 환경에서 다운되는 현상을 재현했을 때의 로그 메시지입니다.


## 12.10.FC12W1

11:20:01  Assert Failed: Buffer modified in inconsistent chunk.

11:20:01  IBM Informix Dynamic Server Version 12.10.FC12W1WE

11:20:01   Who: Session(87, informix@pilma01, 39452766, 700000020593858)

                Thread(222, sqlexec, 700000020553068, 10)

                File: rsdebug.c Line: 1047

11:20:01   Results: Chunk 13 is being taken OFFLINE.

11:20:01   Action: Restore space containing this chunk from the archive.

11:20:01  stack trace for pid 36175890 written to /work2/ifx1210fc12w1we/tmp/af.4c6a350

11:20:02   See Also: /work2/ifx1210fc12w1we/tmp/af.4c6a350, shmem.4c6a350.0

11:20:10  Buffer modified in inconsistent chunk.

11:20:11  Assert Failed: INFORMIX-OnLine Must ABORT

        Critical media failure.

11:20:11  IBM Informix Dynamic Server Version 12.10.FC12W1WE

11:20:11   Who: Session(87, informix@pilma01, 39452766, 700000020593858)

                Thread(222, sqlexec, 700000020553068, 10)

                File: rsmirror.c Line: 2080

11:20:11  stack trace for pid 36175890 written to /work2/ifx1210fc12w1we/tmp/af.4c6a350

11:20:12   See Also: /work2/ifx1210fc12w1we/tmp/af.4c6a350

11:20:19  Thread ID 222 will NOT be suspended because

          it is in a critical section.

11:20:19   See Also: /work2/ifx1210fc12w1we/tmp/af.4c6a350

11:20:19  rsmirror.c, line 2080, thread 222, proc id 36175890, INFORMIX-OnLine Must ABORT

        Critical media failure..

11:20:19  Fatal error in ADM VP at mt_fn.c:14593

11:20:19  Unexpected virtual processor termination: pid = 36175890, exit status = 0x1.

11:20:19  PANIC: Attempting to bring system down


## 14.10.FC1DE

12:46:54  Assert Failed: Buffer modified in inconsistent chunk.

12:46:54  IBM Informix Dynamic Server Version 14.10.FC1DE

12:46:54   Who: Session(46, informix@ifxdb1, 62804, 0x4526fbc8)

                Thread(55, sqlexec, 4522d8c8, 1)

                File: rsdebug.c Line: 908

12:46:54   Results: Chunk 1 is being taken OFFLINE.

12:46:54   Action: Restore space containing this chunk from the archive.

12:46:54  stack trace for pid 62571 written to /opt/IBM/Informix_Software_Bundle/tmp/af.41fb7ad

12:46:54   See Also: /opt/IBM/Informix_Software_Bundle/tmp/af.41fb7ad, shmem.41fb7ad.0

12:46:57  Buffer modified in inconsistent chunk.

12:46:58  Assert Failed: INFORMIX-OnLine Must ABORT

        Critical media failure.

12:46:58  IBM Informix Dynamic Server Version 14.10.FC1DE

12:46:58   Who: Session(46, informix@ifxdb1, 62804, 0x4526fbc8)

                Thread(55, sqlexec, 4522d8c8, 1)

                File: rsmirror.c Line: 2062

12:46:58  stack trace for pid 62571 written to /opt/IBM/Informix_Software_Bundle/tmp/af.41fb7ad

12:46:58   See Also: /opt/IBM/Informix_Software_Bundle/tmp/af.41fb7ad

12:47:02  Thread ID 55 will NOT be suspended because

          it is in a critical section.

12:47:02   See Also: /opt/IBM/Informix_Software_Bundle/tmp/af.41fb7ad

12:47:02  Starting crash time check of:

12:47:02  1. memory block headers

12:47:02  2. stacks

12:47:02  Crash time checking found no problems

12:47:02  rsmirror.c, line 2062, thread 55, proc id 62571, INFORMIX-OnLine Must ABORT

        Critical media failure..

12:47:02  The Master Daemon Died

12:47:02  PANIC: Attempting to bring system down



관련 내용으로 IBM에 기술지원을 요청했었습니다.

해당 문제는 해외에서 발생한 사례가 이미 있었다고 하고 재현 시나리오도 구체적이진 않지만 존재했습니다.

관련 문제를 서술한 문서의 링크는 아래입니다.

http://www-01.ibm.com/support/docview.wss?crawler=1&uid=swg1IT27997


장애 재현시의 메시지 로그에서 보이는 assert failure file 내용을 살펴보니 해당 사용자 스레드의 stack trace를 확인할 수 있었습니다.


0x00000001000af9cc (oninit)afstack

0x00000001000aeb5c (oninit)afhandler

0x00000001000af038 (oninit)affail_interface

0x00000001001b8844 (oninit)buffcheck

0x00000001002371a0 (oninit)buffput

0x0000000100b88640 (oninit)ckpgversion

0x0000000100b87af4 (oninit)rewrecord

0x0000000100b870ec (oninit)rsrewrec

0x000000010071ab00 (oninit)fmrewrec

0x00000001008382a0 (oninit)aud_sqisrewrec

0x0000000100d40a90 (oninit)doupdate

0x0000000100d3ff2c (oninit)chkrowcons

0x000000010114ea04 (oninit)dodmlrow

0x0000000101150eac (oninit)dodelupd

0x000000010083ee30 (oninit)aud_dodelupd

0x0000000100d1ec24 (oninit)excommand

0x00000001008c8590 (oninit)sq_execute

0x00000001008103ac (oninit)sqmain

0x00000001014d6898 (oninit)listen_verify

0x00000001014d530c (oninit)spawn_thread

0x0000000101482ae0 (oninit)th_init_initgls

0x00000001018f86e0 (oninit)startup


defect IT27997에 대해 서술한 내용과 상당히 유사한 stack trace 임을 알 수 있었습니다.

stack trace 중에서 ckpgversion function 부분이 문제인 듯 합니다.

그리고 12.10.FC12 버전부터 In-place alter 기능이 개선되었다고 알려져있는데, 이 개선으로 인해 defect가 발생한 것이 아닌가 생각도 듭니다. 물론 제 추측이기 때문에 정확한 원인으로 보기는 어렵습니다.

IIUG2018의 발표자료중 Jeff McMahon and Nick Geib가 발표한 What’s New in Informix 장표를 살표보면 VARCHAR 에서 VARCHAR 간 (smaller or larger) 사이즈를 변경하는 유형도 In-place alter 방식으로 이루어진다고 나와 있습니다.


아래는 위의 IT27997의 내용을 토대로 작성한 장애재현 스크립트 내용입니다.

테스트용 데이터는 60자 고정길이 필드 한개로 만드시면 재현이 쉽습니다.


drop table test;

create table test (a varchar(60));


load from test.unl insert into test;


alter table test add b int;

alter table test add c varchar(5);

alter table test add d varchar(5);

alter table test add e varchar(5);

alter table test modify c varchar(1);

alter table test modify d varchar(1);

alter table test modify e varchar(1);


update test set a=' qui officia deserunt mollit anim id est laborum.Lorem ip';


해당 문제는 12.10.FC12 및 12.10.FC12W1 에서 발생하는 문제이므로 해당버전을 사용중이라면 IBM에 패치버전을 요청하시거나 12.10.FC11 이하 버전으로 다운그레이드하면 문제가 발생하지 않습니다.


참고가 되시길 바랍니다.

728x90
728x90

Informix Version : Informix 12.10.FC5W1

OS : Windows 2012 R2

 

윈도우 2012에 인포믹스 설치 중 아래와 같은 오류가 발생했습니다. 찾아보니 설치프로그램의 호환성 이슈인 것 같습니다. 설치프로그램의 호환 모드를 Windows 7으로 했을 때 잘 설치되었습니다.

 

The Application has Unexpectedly Quit



Invocation of this Java Application has caused an

Invocation TargetException. This application will not exit (LAX)



ZeroGu6: Windows DLL failed to load
    at ZeroGa4.b(DashoA10*..)
    at ZeroGa4.b(DashoA10*..)
    at com.zerog.ia.installer.LifeCycleManager.b(DashoA10*..)
    at com.zerog.ia.installer.LifeCycleManager.a(DashoA10*..)
    at com.zerog.ia.installer.Main.main(DashoA10*..)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
    at java.lang.reflect.Method.invoke(Method.java:611)
    at com.zerog.lax.LAX.launch(DashoA10*..)
    at com.zerog.lax.LAX.main(DashoA10*..)

 

http://www-01.ibm.com/support/docview.wss?uid=swg21686842

728x90

+ Recent posts