<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Michael</title>
    <description>The latest articles on DEV Community by Michael (@michaelfv).</description>
    <link>https://dev.to/michaelfv</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3830930%2F34d5c2f8-f162-4df3-865b-34a96a64ac17.png</url>
      <title>DEV Community: Michael</title>
      <link>https://dev.to/michaelfv</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/michaelfv"/>
    <language>en</language>
    <item>
      <title>Triggered Stored Procedures in GBase 8s: Adding Complex Logic to Triggers</title>
      <dc:creator>Michael</dc:creator>
      <pubDate>Mon, 30 Mar 2026 15:49:40 +0000</pubDate>
      <link>https://dev.to/michaelfv/triggered-stored-procedures-in-gbase-8s-adding-complex-logic-to-triggers-3med</link>
      <guid>https://dev.to/michaelfv/triggered-stored-procedures-in-gbase-8s-adding-complex-logic-to-triggers-3med</guid>
      <description>&lt;p&gt;In GBase 8s, triggers alone do not support features like RAISE EXCEPTION or conditional logic — those belong to stored procedures. But when you need such logic inside a trigger, you can use a triggered stored procedure. This article walks through an INSERT trigger example that validates data and throws an exception if needed.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create Sample Tables
We need two tables: tab1 (the target for inserts) and tab2 (to store existing IDs).
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;tab1&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;tab2&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;uptime&lt;/span&gt; &lt;span class="nb"&gt;DATETIME&lt;/span&gt; &lt;span class="nb"&gt;YEAR&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="k"&gt;SECOND&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;CURRENT&lt;/span&gt; &lt;span class="nb"&gt;YEAR&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="k"&gt;SECOND&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create the Stored Procedure
The stored procedure checks whether the new ID already exists in tab2. If it does, it raises an exception.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;proc_tri_insert_tab1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;REFERENCING&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;tab1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tab2&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
        &lt;span class="n"&gt;RAISE&lt;/span&gt; &lt;span class="n"&gt;EXCEPTION&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;746&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'ID exists!'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create the Trigger
Now attach the stored procedure to the INSERT event on tab1.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TRIGGER&lt;/span&gt; &lt;span class="n"&gt;tri_insert_tab1&lt;/span&gt; &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;tab1&lt;/span&gt;
    &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;EACH&lt;/span&gt; &lt;span class="k"&gt;ROW&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;EXECUTE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;proc_tri_insert_tab1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;TRIGGER&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Test It Out&lt;br&gt;
Insert a row into tab1 with an ID that already exists in tab2. The trigger fires, calls the stored procedure, and the exception is raised:&lt;br&gt;
&lt;code&gt;INSERT INTO tab1 VALUES (2, 'testssdadsfas');&lt;/code&gt;&lt;br&gt;
Output:&lt;br&gt;
&lt;code&gt;746: ID exists!&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Summary&lt;br&gt;
With triggered stored procedures, the gbase database extends the power of triggers — you can now include complex checks, conditionals, and even custom exceptions. This approach is invaluable for enforcing strict business rules at the data‑entry level.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Have you used triggered stored procedures in your projects? Share your experience in the comments! 👇&lt;/p&gt;

</description>
      <category>gbase</category>
      <category>database</category>
      <category>数据库</category>
    </item>
    <item>
      <title>Implementing split_part Function in GBase 8s: Two Practical Approaches</title>
      <dc:creator>Michael</dc:creator>
      <pubDate>Mon, 30 Mar 2026 15:41:50 +0000</pubDate>
      <link>https://dev.to/michaelfv/implementing-splitpart-function-in-gbase-8s-two-practical-approaches-i8e</link>
      <guid>https://dev.to/michaelfv/implementing-splitpart-function-in-gbase-8s-two-practical-approaches-i8e</guid>
      <description>&lt;p&gt;GBase 8s does not provide a built‑in split_part function like PostgreSQL. However, using the existing SUBSTRING_INDEX function or manual character parsing, we can easily achieve the same functionality. This article introduces two implementation methods with practical examples.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What Does split_part Do?
The split_part function splits a string by a delimiter and returns the n‑th field.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;code&gt;split_part('aa,bb,cc,dd', ',', 3) → 'cc'&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Method 1: Using SUBSTRING_INDEX
GBase 8s provides SUBSTRING_INDEX, which extracts a substring up to a specified number of occurrences. This makes the implementation very straightforward.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;split_part2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;split_part2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;str_in&lt;/span&gt; &lt;span class="n"&gt;lvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;separator_in&lt;/span&gt; &lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;field_in&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;RETURNING&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;str_len&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;pos_curr&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;count_field&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;pos_char&lt;/span&gt; &lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;field_in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;count_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;str_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;LENGTH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str_in&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;-- Count delimiters to know total fields&lt;/span&gt;
    &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;pos_curr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;str_len&lt;/span&gt;
        &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;pos_char&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SUBSTR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pos_curr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;pos_char&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;separator_in&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
            &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;count_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count_field&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;-- If requested field exceeds actual count, return NULL&lt;/span&gt;
    &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;field_in&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;count_field&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
        &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;ELSE&lt;/span&gt;
        &lt;span class="c1"&gt;-- Take the first `field_in` segments, then the last one&lt;/span&gt;
        &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;SUBSTRING_INDEX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;SUBSTRING_INDEX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;separator_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field_in&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;separator_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pros: Simple logic, uses built‑in functions, easy to read.&lt;br&gt;
Cons: Requires one pass to count delimiters (negligible for most strings).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Method 2: Pure Character Parsing
This version does not rely on SUBSTRING_INDEX — it manually scans the string to locate the desired field.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;split_part&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;split_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;str_in&lt;/span&gt; &lt;span class="n"&gt;lvarchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;separator_in&lt;/span&gt; &lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;field_in&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;RETURNING&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;str_len&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;pos_curr&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;substr_start&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;substr_length&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;DEFINE&lt;/span&gt; &lt;span class="n"&gt;pos_char&lt;/span&gt; &lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;field_in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;substr_start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;substr_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;str_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;LENGTH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str_in&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;pos_curr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;str_len&lt;/span&gt;
        &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;pos_char&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SUBSTR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pos_curr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;pos_char&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;separator_in&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
            &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;field_in&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;field_in&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;-- Locate start of the target field&lt;/span&gt;
        &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;field_in&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;substr_start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
            &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;substr_start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pos_curr&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;DECODE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos_char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;separator_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;-- Locate end of the target field&lt;/span&gt;
        &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;field_in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
            &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;substr_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pos_curr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;EXIT&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;-- Handle edge cases (field is the last one or string ends)&lt;/span&gt;
    &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;substr_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
        &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;substr_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;str_len&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;substr_start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
        &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;substr_start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;str_len&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;substr_length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;substr_start&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
        &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;substr_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;ELSE&lt;/span&gt;
        &lt;span class="n"&gt;LET&lt;/span&gt; &lt;span class="n"&gt;substr_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;substr_length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;substr_start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;NVL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SUBSTRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str_in&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;substr_start&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;substr_length&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pros: No dependency on SUBSTRING_INDEX; fully portable logic.&lt;br&gt;
Cons: More complex code; requires careful handling of positions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Example Usage
Take the string:'aa,bb,cc,dd'
Call both functions to get the third field:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;split_part2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'aa,bb,cc,dd'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;dual&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;split_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'aa,bb,cc,dd'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;dual&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both return:&lt;br&gt;
&lt;code&gt;cc&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Summary
Although GBase 8s lacks a native split_part, we’ve built two reliable implementations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Method 1 is shorter and cleaner — ideal for most cases.&lt;/p&gt;

&lt;p&gt;Method 2 offers independence from any specific built‑in function.&lt;/p&gt;

&lt;p&gt;Both functions have been tested and are ready to use in your GBase 8s environment. Have other string processing needs? Feel free to drop a comment below! 👇&lt;/p&gt;

</description>
      <category>gbase</category>
      <category>database</category>
      <category>数据库</category>
    </item>
    <item>
      <title>GBase 8a Performance Troubleshooting: From Slow Query Detection to Primary‑Replica Consistency</title>
      <dc:creator>Michael</dc:creator>
      <pubDate>Thu, 26 Mar 2026 10:41:27 +0000</pubDate>
      <link>https://dev.to/michaelfv/gbase-8a-performance-troubleshooting-from-slow-query-detection-to-primary-replica-consistency-16i2</link>
      <guid>https://dev.to/michaelfv/gbase-8a-performance-troubleshooting-from-slow-query-detection-to-primary-replica-consistency-16i2</guid>
      <description>&lt;p&gt;In day‑to‑day operations with GBase 8a, the real headache often isn’t creating tables or databases — it’s the “production issues” that appear after the system goes live. A SQL query that used to run smoothly suddenly becomes slow. The cluster looks healthy, but business starts seeing result fluctuations, uneven node execution times, or local replica inconsistencies. These problems are rarely isolated. Drawing from the GBase community’s collective experience, this article lays out a structured troubleshooting path — from slow query detection all the way to primary‑replica consistency handling.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Don’t Rewrite SQL First — Figure Out Where It’s Slow
The most common reflex when a query slows down is to immediately rewrite JOINs, break down subqueries, or add filters. That approach isn’t wrong, but it should come after you know whether the entire SQL is slow or just a few nodes are dragging it down.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GBase 8a provides the parameter gcluster_dql_statistic_threshold. When enabled, it records SQL execution information for queries exceeding the threshold into the system tables gclusterdb.sys_sqls and gclusterdb.sys_sql_elapsepernode. Meanwhile, the in‑memory table information_schema.SELECT_STATISTIC lets you observe currently running queries per node. The default value is 0 (disabled); when set to a positive value, only queries running longer than that threshold are recorded.&lt;/p&gt;

&lt;p&gt;Practical approach: Set a reasonable threshold, then examine node‑level differences.&lt;br&gt;
&lt;code&gt;set global gcluster_dql_statistic_threshold = 3000;&lt;/code&gt;&lt;br&gt;
Check recently recorded slow SQLs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;gclusterdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sys_sqls&lt;/span&gt;
&lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;create_time&lt;/span&gt; &lt;span class="k"&gt;desc&lt;/span&gt;
&lt;span class="k"&gt;limit&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then look at the execution time distribution for a specific SQL across nodes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;gclusterdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sys_sql_elapsepernode&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;sql_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'replace_with_actual_sql_id'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If most nodes are fast but a few are significantly slower, the problem is not “bad SQL” — it’s likely node resource imbalance, data skew, execution blocking, or even a node‑level issue. Conversely, if all nodes are slow, then the bottleneck is global: the SQL logic itself, large intermediate results, or configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When Node Times Are Uneven, Suspect Data Skew First
In a distributed analytical database like GBase 8a, many “slow queries” aren’t due to global performance deficiency — they’re caused by a few nodes doing most of the work.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Scenarios like distinct, group by, dynamic hash redistribution, or joining multiple small tables can easily trigger data skew. Relevant optimization parameters include gcluster_hash_redistribute_join_optimize and gcluster_hash_redistribute_groupby_optimize.&lt;/p&gt;

&lt;p&gt;A classic example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;region_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;distinct&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fact_order&lt;/span&gt;
&lt;span class="k"&gt;group&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;region_code&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks simple, but if region_code is highly skewed — say, a few values dominate — a handful of nodes will stay busy while others finish quickly. Even if total cluster CPU isn’t maxed out, query time gets dragged down by the slowest nodes.&lt;/p&gt;

&lt;p&gt;When node‑level time differences are large, a solid sequence is: confirm whether it’s skew; then determine if the skew comes from the original distribution key or from dynamic redistribution during execution; finally decide whether to adjust the data model, rewrite the SQL, or tune parameters.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Slow Queries Aren’t Always About Scanning — Intermediate Results Can Be Heavy
In many analytical environments, the real bottleneck isn’t “reading data” — it’s oversized intermediate results, too many temporary objects, or high data exchange costs after redistribution.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, in a wide‑table scenario, this kind of query easily blows up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fact_a&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;join&lt;/span&gt; &lt;span class="n"&gt;fact_b&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
  &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stat_date&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2026-01-01'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem isn’t necessarily the JOIN itself — it’s that select * makes the intermediate result set explode, and everything downstream (sorting, aggregation, data exchange) becomes heavier. For an analytical system like GBase 8a, a better practice is to select only necessary columns, push filters down as early as possible, and reduce the data volume before joining large tables.&lt;/p&gt;

&lt;p&gt;When you suspect the bottleneck is not at the SQL text level but within the execution chain, logs become critical. express.log records important events inside the express engine, and gcluster_log_level controls log verbosity.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Look at Local Logs Alongside SQL Statistics
System tables alone aren’t always enough. Some problems don’t show up in SQL statistics but appear first in service, recovery, loading, or daemon logs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;express.log: important events and exceptions from the execution engine.&lt;br&gt;
system.log: stack traces when a service crashes.&lt;br&gt;
gc_recover: event recovery processes.&lt;br&gt;
gcware.log: node status, resource conditions, and multi‑replica operations.&lt;br&gt;
Also loader_logs, loader_result, gcinstall.log, replace.log, etc.&lt;/p&gt;

&lt;p&gt;These logs are invaluable during troubleshooting. For instance, if node‑level statistics show one node is clearly abnormal, check its logs for crashes, recovery, load conflicts, disk issues, or resource exhaustion.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Audit Information Isn’t Just for Compliance — It Helps Troubleshooting Too
Many environments only look at audit tables when compliance demands it, but they’re also useful for root‑cause analysis. Combining “who did what when” with “which node was slow and how slow” often helps connect the dots faster.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If a statistical SQL suddenly slows down, node‑level stats tell you that it’s slow, but they don’t tell you what happened in the preceding hours. Pairing that with recent bulk loads, deletes, table changes, or parameter modifications makes the investigation much more efficient.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When Problems Start Looking Like Replica Inconsistency, Stop Purely Performance‑Focused Diagnosis
Some issues that seem like query anomalies are actually primary‑replica consistency problems. Common causes include inconsistent local parameters, power outages, server crashes, RAID/driver issues, virtual machine failures, or manual misoperations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GBase 8a uses direct I/O for writes; the database only considers a write successful after confirmation, but if the underlying environment fails, there’s still a risk of logical success without physical durability.&lt;/p&gt;

&lt;p&gt;The parameter gcluster_suffix_consistency_resolve defaults to 0 (do not resolve shard consistency). When set to 1, it attempts resolution. This feature requires at least three host nodes; a two‑node cluster may not support all capabilities.&lt;/p&gt;

&lt;p&gt;If you encounter any of these symptoms, stop treating it as a normal slow‑query problem:&lt;/p&gt;

&lt;p&gt;The same table returns unstable results at different times.&lt;br&gt;
After a node recovers, local queries start erroring.&lt;br&gt;
DML operations appear successful but subsequent reads behave abnormally.&lt;br&gt;
Recent power outages, node failures, manual event deletions, or local parameter changes.&lt;/p&gt;

&lt;p&gt;At this point, first verify whether a consistency issue exists — otherwise, you’ll waste time on SQL tuning that can’t solve the real problem.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A Cleaner Troubleshooting Path
Putting the above together gives a repeatable sequence:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 1: Determine whether the problem is “global slowdown” or “a few nodes are significantly slower.” Use gcluster_dql_statistic_threshold together with sys_sqls and sys_sql_elapsepernode.&lt;br&gt;
Step 2: If it’s node‑specific, check for data skew, dynamic redistribution, or hot spots triggered by distinct/group by/JOINs. Look at execution logs to see if any stage is unusually long.&lt;br&gt;
Step 3: If it’s not purely a performance issue but involves unstable results, post‑recovery anomalies, or inconsistent reads/writes, shift focus to primary‑replica consistency and underlying environment events. Don’t keep tweaking SQL.&lt;/p&gt;

&lt;p&gt;This sequence prevents the two extremes: rewriting SQL without evidence, or rebuilding everything at the first sign of trouble. Narrow down the scope first, then decide whether to modify SQL, adjust parameters, examine logs, or handle consistency issues.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Things Often Overlooked in Production&lt;br&gt;
Don’t rely on average time: In a distributed environment, averages hide node‑level drags. The slowest node often determines overall query time.&lt;br&gt;
Parameters aren’t magic bullets: They’re optimization levers for specific scenarios, not universal fixes.&lt;br&gt;
Don’t ignore the underlying environment: Power outages, crashes, drivers, and virtual machine issues are repeatedly mentioned in consistency‑related content — database behavior often reflects underlying conditions.&lt;br&gt;
Combine logs with statistics: System tables tell you which SQL is slow and where; logs tell you why it’s slow and whether anomalies occurred alongside it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Conclusion&lt;br&gt;
The hardest part of GBase 8a performance and stability isn’t finding a “magic parameter” — it’s breaking the problem into the right layers. A slow query may not be poorly written SQL; it could be node skew. A healthy cluster status doesn’t guarantee a healthy execution path. And once a problem reaches the primary‑replica consistency layer, ordinary SQL tuning will only lead you in circles.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The GBase community’s resources on node‑level statistics, execution logs, parameter tuning, and consistency handling together offer a practical methodology: first observe node differences, then analyze execution phases, then decide whether it’s a distribution/intermediate‑result issue, and finally determine if you need to move into consistency troubleshooting.&lt;/p&gt;

</description>
      <category>gbase</category>
      <category>database</category>
      <category>数据库</category>
    </item>
    <item>
      <title>Make Your Queries 10x Faster with GBase 8a Rough Index</title>
      <dc:creator>Michael</dc:creator>
      <pubDate>Thu, 26 Mar 2026 10:10:18 +0000</pubDate>
      <link>https://dev.to/michaelfv/make-your-queries-10x-faster-with-gbase-8a-rough-index-9fk</link>
      <guid>https://dev.to/michaelfv/make-your-queries-10x-faster-with-gbase-8a-rough-index-9fk</guid>
      <description>&lt;p&gt;When working with big data analytics in GBase 8a, you’ve probably noticed something strange: the same SQL query can be incredibly fast sometimes, yet painfully slow at others. The key difference often comes down to whether you’re leveraging Rough Index — a lightweight indexing mechanism built into the GBase 8a columnar storage engine.&lt;/p&gt;

&lt;p&gt;In this article, I’ll walk you through what Rough Index is, how it works, and how to use it effectively to dramatically speed up your queries.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What Is Rough Index?
Rough Index (RI) is a block‑level index that doesn’t store exact row positions like a B‑Tree. Instead, for each data block (typically 64KB or 128KB), it records the minimum and maximum values of a column within that block.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example: Suppose the amount column in an orders table is split into 1,000 blocks. Rough Index might store:&lt;/p&gt;

&lt;p&gt;Block 1: min=10, max=500&lt;br&gt;
Block 2: min=501, max=1200&lt;br&gt;
Block 3: min=1201, max=2500&lt;br&gt;
…&lt;/p&gt;

&lt;p&gt;Now when you run a query like WHERE amount &amp;gt; 2000, the GBase 8a optimizer scans the Rough Index first. Any block whose maximum value is ≤ 2000 is skipped entirely — no actual data is read. This is called block pruning.&lt;/p&gt;

&lt;p&gt;When data is well‑ordered, Rough Index can prune 90% or more of I/O operations, making your queries 5 to 10 times faster with no extra hardware.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How to Check If Rough Index Is Working
Use EXPLAIN to View the Execution Plan
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;EXPLAIN&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;create_time&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2024-01-01'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you see “Rough Index Scan” in the output, or the number of blocks_scanned is much smaller than the total block count, Rough Index is active.&lt;/p&gt;

&lt;p&gt;Query the System View&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GBASE_ROUGH_INDEX&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;table_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'orders'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This view shows which columns have Rough Index enabled and their current status.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How to Maximize Rough Index Effectiveness
Tip 1: Keep Data Ordered During Import
Rough Index pruning works best when data is sorted by the column you frequently filter on. If values are randomly distributed across blocks, each block’s min/max range becomes wide, and pruning becomes less effective.
Best practice: Sort your input file by the filter column before loading.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;LOAD&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt; &lt;span class="n"&gt;INFILE&lt;/span&gt; &lt;span class="s1"&gt;'/data/orders_sorted.csv'&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="n"&gt;FIELDS&lt;/span&gt; &lt;span class="n"&gt;TERMINATED&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="s1"&gt;','&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;create_time&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;-- Make sure the file is sorted by create_time before loading&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tip 2: Rebuild Rough Index After Updates&lt;br&gt;
If your table undergoes many updates or out‑of‑order inserts, you can manually rebuild the index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;REBUILD&lt;/span&gt; &lt;span class="n"&gt;ROUGH&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tip 3: Use Range Filters for Best Results&lt;br&gt;
Rough Index performs best with range predicates (&amp;gt;, &amp;lt;, BETWEEN). It works less well with IN lists or !=.&lt;br&gt;
✅ Good: Range query&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;create_time&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="s1"&gt;'2024-01-01'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="s1"&gt;'2024-03-31'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❌ Not ideal: Discrete value list&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Summary
Rough Index is a powerful, built‑in performance feature in the gbase database. By understanding its block‑pruning mechanism and designing your data loading and queries accordingly, you can achieve massive speedups without adding hardware.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you’re using GBase 8a for analytical workloads, take a moment to check your Rough Index usage — it might be the secret to making your queries run 10x faster!&lt;/p&gt;

</description>
      <category>gbase</category>
      <category>database</category>
      <category>数据库</category>
    </item>
    <item>
      <title>Boost JDBC Performance with GBase 8s: Understanding IFX_AUTOFREE</title>
      <dc:creator>Michael</dc:creator>
      <pubDate>Tue, 24 Mar 2026 12:45:40 +0000</pubDate>
      <link>https://dev.to/michaelfv/boost-jdbc-performance-with-gbase-8s-understanding-ifxautofree-48i6</link>
      <guid>https://dev.to/michaelfv/boost-jdbc-performance-with-gbase-8s-understanding-ifxautofree-48i6</guid>
      <description>&lt;p&gt;When working with JDBC, repeatedly creating and closing &lt;code&gt;ResultSet&lt;/code&gt; and &lt;code&gt;Statement&lt;/code&gt; objects can generate unnecessary network round trips. The GBase 8s JDBC driver offers a handy parameter — &lt;code&gt;IFX_AUTOFREE&lt;/code&gt; — that helps reduce this overhead and improves performance in high‑query scenarios.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Does IFX_AUTOFREE Do?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;IFX_AUTOFREE&lt;/code&gt; is a boolean parameter (&lt;code&gt;0&lt;/code&gt; = disabled, &lt;code&gt;1&lt;/code&gt; = enabled). When enabled, the server automatically frees the cursor as soon as the client calls &lt;code&gt;ResultSet.close()&lt;/code&gt;. Consequently, when &lt;code&gt;Statement.close()&lt;/code&gt; is later invoked, the JDBC driver does &lt;strong&gt;not&lt;/strong&gt; send an extra cursor‑release message to the server, saving one network round trip per statement.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Enable It
&lt;/h2&gt;

&lt;p&gt;You can enable &lt;code&gt;IFX_AUTOFREE&lt;/code&gt; in two ways:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Via the JDBC URL
&lt;/h3&gt;

&lt;p&gt;jdbc:gbasedbt-sqli://:/:IFX_AUTOFREE=1;DB_LOCALE=en_US.819&lt;/p&gt;

&lt;p&gt;text&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Via a Properties Object
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;java&lt;/span&gt;
&lt;span class="nc"&gt;Properties&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Properties&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IFX_AUTOFREE"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DriverManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConnection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When to Use It&lt;br&gt;
This parameter shines in scenarios where you run many short queries, such as in loops that repeatedly execute SELECT statements and immediately close the result set. By eliminating one network round trip per query, it can significantly boost throughput.&lt;/p&gt;

&lt;p&gt;Performance Test&lt;br&gt;
The following examples compare execution times for 1000 queries under different configurations.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Without IFX_AUTOFREE (Baseline)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;java&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"jdbc:gbasedbt-sqli://192.168.226.180:12888/testdb:IFX_AUTOFREE=0;DB_LOCALE=en_US.819"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Inside loop: try (PreparedStatement ps = conn.prepareStatement("SELECT * FROM t1");&lt;/span&gt;
&lt;span class="c1"&gt;//                ResultSet rs = ps.executeQuery()) { rs.next(); }&lt;/span&gt;
&lt;span class="c1"&gt;// Output: time:2898 ms&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;With IFX_AUTOFREE=1
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;java&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"jdbc:gbasedbt-sqli://192.168.226.180:12888/testdb:IFX_AUTOFREE=1;DB_LOCALE=en_US.819"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Same loop using PreparedStatement + ResultSet&lt;/span&gt;
&lt;span class="c1"&gt;// Output: time:2343 ms&lt;/span&gt;
&lt;span class="nl"&gt;Result:&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;faster&lt;/span&gt; &lt;span class="n"&gt;than&lt;/span&gt; &lt;span class="n"&gt;baseline&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Using Statement Instead of PreparedStatement (with AUTOFREE=1)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;java&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"jdbc:gbasedbt-sqli://192.168.226.180:12888/testdb:IFX_AUTOFREE=1;DB_LOCALE=en_US.819"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Inside loop: try (Statement stmt = conn.createStatement();&lt;/span&gt;
&lt;span class="c1"&gt;//                ResultSet rs = stmt.executeQuery("SELECT * FROM t1")) { rs.next(); }&lt;/span&gt;
&lt;span class="c1"&gt;// Output: time:2376 ms&lt;/span&gt;
&lt;span class="nc"&gt;Performance&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;similar&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="nc"&gt;PreparedStatement&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Combining with OPTOFC
OPTOFC (Open‑Fetch‑Close) is another optimization parameter. When used together with IFX_AUTOFREE, it can further reduce network round trips:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;java&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"jdbc:gbasedbt-sqli://192.168.226.180:12888/testdb:IFX_AUTOFREE=1;OPTOFC=1;DB_LOCALE=en_US.819"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Loop as in example 2&lt;/span&gt;
&lt;span class="c1"&gt;// Output: time:1228 ms&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The combination yields a dramatic improvement (1228 ms, about 58% faster than baseline).&lt;/p&gt;

&lt;p&gt;Summary&lt;br&gt;
IFX_AUTOFREE is a simple yet powerful JDBC parameter in the gbase database ecosystem. By enabling it, you can eliminate one network round trip per statement closure, resulting in noticeable performance gains for high‑volume query workloads. For even better results, consider pairing it with OPTOFC.&lt;/p&gt;

&lt;p&gt;If you have any questions or want to share your own experiences, feel free to leave a comment! 🚀&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Understanding the ISNULL() Function in GBase 8s</title>
      <dc:creator>Michael</dc:creator>
      <pubDate>Tue, 24 Mar 2026 12:23:38 +0000</pubDate>
      <link>https://dev.to/michaelfv/understanding-the-isnull-function-in-gbase-8s-2370</link>
      <guid>https://dev.to/michaelfv/understanding-the-isnull-function-in-gbase-8s-2370</guid>
      <description>&lt;p&gt;Handling &lt;code&gt;NULL&lt;/code&gt; values is a common challenge in database queries. The gbase database provides a flexible &lt;code&gt;ISNULL()&lt;/code&gt; function that works in two forms: with two parameters or with one. Let's dive into how it works and see some practical examples.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two‑Parameter Form: &lt;code&gt;ISNULL(a, b)&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;a&lt;/code&gt; is &lt;strong&gt;not&lt;/strong&gt; &lt;code&gt;NULL&lt;/code&gt;, returns &lt;code&gt;a&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;a&lt;/code&gt; is &lt;code&gt;NULL&lt;/code&gt;, returns &lt;code&gt;b&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If both are &lt;code&gt;NULL&lt;/code&gt;, returns &lt;code&gt;NULL&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This behaves like returning the first non‑NULL value from left to right.&lt;/p&gt;

&lt;h2&gt;
  
  
  One‑Parameter Form: &lt;code&gt;ISNULL(a)&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;a&lt;/code&gt; is &lt;code&gt;NULL&lt;/code&gt;, returns the boolean &lt;code&gt;t&lt;/code&gt; (true).&lt;/li&gt;
&lt;li&gt;Otherwise, returns &lt;code&gt;f&lt;/code&gt; (false).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is useful for checking whether a column or expression is &lt;code&gt;NULL&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Two‑Parameter Examples
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;DUAL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;-- Result: 12&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'aa'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;DUAL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- Result: 'aa'&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;DUAL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- Result: NULL&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'abc'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'ef'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;DUAL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- Result: 'abc'&lt;/span&gt;
&lt;span class="n"&gt;One&lt;/span&gt;&lt;span class="err"&gt;‑&lt;/span&gt;&lt;span class="k"&gt;Parameter&lt;/span&gt; &lt;span class="n"&gt;Examples&lt;/span&gt;
&lt;span class="k"&gt;sql&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'aa'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;DUAL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;-- Result: 'f'&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;DUAL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;-- Result: 't'&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'null'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;DUAL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- Result: 'f'&lt;/span&gt;
&lt;span class="nb"&gt;Real&lt;/span&gt;&lt;span class="err"&gt;‑&lt;/span&gt;&lt;span class="n"&gt;World&lt;/span&gt; &lt;span class="n"&gt;Scenario&lt;/span&gt;
&lt;span class="n"&gt;Let&lt;/span&gt;&lt;span class="s1"&gt;'s create a table and use ISNULL() in a CTE to identify NULL values and compute aggregations.

sql
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (id INT, col1 INT, col2 INT);
INSERT INTO t1 VALUES (1,1,1), (2,NULL,NULL), (3,4,4), (4,0,0);

WITH tmp1 AS (
  SELECT id, col1, ISNULL(col1) AS null_flag, SUM(col2) AS total_col2
  FROM t1
  GROUP BY id, col1
),
tmp2 AS (
  SELECT id, col1, ISNULL(tmp1.total_col2) AS null_col2
  FROM tmp1
  WHERE id &amp;gt; 1 AND ISNULL(col1) = '&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="s1"&gt;'
)
SELECT id, col1, null_col2 FROM tmp2;
-- Output: id=2, col1=NULL, null_col2=1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Summary&lt;br&gt;
The ISNULL() function in GBase 8s provides a clean way to handle NULL values. Use the two‑parameter form to return a fallback value, and the one‑parameter form to quickly test for NULL. Whether you're writing simple queries or building complex reports, this function is a handy tool in your SQL toolbox.&lt;/p&gt;

&lt;p&gt;If you have any questions or want to share your own examples, feel free to leave a comment below! 🚀&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>database</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Common Parameters for GBase 8a MPP Cluster Command-Line Clients: gccli and gncli</title>
      <dc:creator>Michael</dc:creator>
      <pubDate>Mon, 23 Mar 2026 15:50:01 +0000</pubDate>
      <link>https://dev.to/michaelfv/common-parameters-for-gbase-8a-mpp-cluster-command-line-clients-gccli-and-gncli-474h</link>
      <guid>https://dev.to/michaelfv/common-parameters-for-gbase-8a-mpp-cluster-command-line-clients-gccli-and-gncli-474h</guid>
      <description>&lt;p&gt;GBase 8a MPP Cluster provides two command-line client tools—&lt;code&gt;gccli&lt;/code&gt; and &lt;code&gt;gncli&lt;/code&gt;—for connecting to the database and executing SQL statements. Mastering their parameters can significantly improve daily operational efficiency. Below is a summary of commonly used options.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connection and Basic Parameters
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-h&lt;/code&gt;: Specifies the IP address(es) to connect to. Multiple IPs can be separated by commas to support high availability.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-u&lt;/code&gt;: Database username.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-p&lt;/code&gt;: Database password.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-P&lt;/code&gt;: Specifies the port number.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-D&lt;/code&gt;: Sets the default database to use.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Execution and Output Control
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-e&lt;/code&gt;: Executes a given SQL statement directly without entering interactive mode.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-E&lt;/code&gt;: Displays results vertically, similar to appending &lt;code&gt;\G&lt;/code&gt; to a query.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-N&lt;/code&gt;: Suppresses column names in the result set, returning only data.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-s&lt;/code&gt;: Enables silent mode, reducing the amount of output.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-vvv&lt;/code&gt;: Outputs detailed execution information, including execution time, which is useful for debugging and performance analysis.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Behavior Control
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-c&lt;/code&gt;: Allows the use of hints. By default, content inside &lt;code&gt;/* */&lt;/code&gt; is treated as a comment and filtered out. With &lt;code&gt;-c&lt;/code&gt;, such content is sent to the server as a hint.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-f&lt;/code&gt;: When executing multiple SQL statements, if an error occurs, the client skips the failing statement and continues with the rest.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-q&lt;/code&gt;: Enables unbuffered output. By default, &lt;code&gt;gccli&lt;/code&gt; buffers the entire result set in memory before displaying it, reducing I/O operations. However, for large result sets, this can consume significant memory. Using &lt;code&gt;-q&lt;/code&gt; outputs results directly, reducing memory pressure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These parameters cover common needs ranging from connection management to execution behavior. Combining them flexibly allows you to adapt to various development and operational scenarios when working with the gbase database. For users of GBASE products, understanding these options helps make daily interactions with the database more efficient and tailored to specific workflows.&lt;/p&gt;

</description>
      <category>gbase</category>
      <category>database</category>
      <category>数据库</category>
    </item>
    <item>
      <title>GBase 8s Trigger with Stored Procedure Example</title>
      <dc:creator>Michael</dc:creator>
      <pubDate>Mon, 23 Mar 2026 15:39:14 +0000</pubDate>
      <link>https://dev.to/michaelfv/gbase-8s-trigger-with-stored-procedure-example-3o2i</link>
      <guid>https://dev.to/michaelfv/gbase-8s-trigger-with-stored-procedure-example-3o2i</guid>
      <description>&lt;p&gt;In GBase 8s, triggers alone do not support conditional logic or exception handling. To implement such functionality, you can combine a trigger with a stored procedure—a pattern often called a triggered stored procedure.&lt;/p&gt;

&lt;p&gt;Below is an example using an INSERT trigger to check for duplicate IDs and raise an exception when needed.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create Sample Tables&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Create two tables: tab1 as the target for insertion, and tab2 to track existing IDs.&lt;/p&gt;

&lt;p&gt;sql&lt;br&gt;
CREATE TABLE tab1 (&lt;br&gt;
    id INTEGER PRIMARY KEY,&lt;br&gt;
    name VARCHAR(40)&lt;br&gt;
);&lt;/p&gt;

&lt;p&gt;CREATE TABLE tab2 (&lt;br&gt;
    id INTEGER,&lt;br&gt;
    name VARCHAR(40),&lt;br&gt;
    uptime DATETIME YEAR TO SECOND DEFAULT CURRENT YEAR TO SECOND&lt;br&gt;
);&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the Stored Procedure&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The stored procedure performs the validation: it checks whether the id being inserted already exists in tab2, and if so, raises an exception.&lt;/p&gt;

&lt;p&gt;sql&lt;br&gt;
CREATE PROCEDURE proc_tri_insert_tab1()&lt;br&gt;
    REFERENCING NEW AS new FOR tab1;&lt;br&gt;
    DEFINE pid INT;&lt;br&gt;
    SELECT COUNT(id) INTO pid FROM tab2 WHERE id = new.id;&lt;br&gt;
    IF pid = 1 THEN&lt;br&gt;
        RAISE EXCEPTION -746, 0, 'ID exists!';&lt;br&gt;
    END IF;&lt;br&gt;
END PROCEDURE;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the Trigger&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Define an INSERT trigger on tab1 that executes the stored procedure for each row.&lt;/p&gt;

&lt;p&gt;sql&lt;br&gt;
CREATE TRIGGER tri_insert_tab1 INSERT ON tab1&lt;br&gt;
    FOR EACH ROW (&lt;br&gt;
        EXECUTE PROCEDURE proc_tri_insert_tab1() WITH TRIGGER REFERENCES&lt;br&gt;
    );&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Test the Behavior&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you insert a row into tab1 with an id that already exists in tab2, the trigger invokes the stored procedure, which raises an exception:&lt;/p&gt;

&lt;p&gt;sql&lt;br&gt;
INSERT INTO tab1 VALUES (2, 'testssdadsfas');&lt;br&gt;
-- Error: 746: ID exists!&lt;br&gt;
``&lt;br&gt;
This technique extends the capabilities of triggers in the gbase database, allowing you to enforce complex business rules seamlessly. For developers working with GBASE products, leveraging triggered stored procedures is a practical way to add sophisticated logic to data modification events while keeping the database design clean and maintainable.&lt;/p&gt;

</description>
      <category>database</category>
      <category>数据库</category>
      <category>gbase</category>
    </item>
  </channel>
</rss>
