I'm german. Please excuse my bad english.
MariaDB version 10.5.18 is much slower than version 10.5.16 in string-manipulation (CONCAT). In version 10.5.16 my code in the bottom needs for 800 records in tmp_tartikel_live 1-2 seconds. In version 10.5.18 my code needs for 800 records in tmp_tartikel_live 20-30 seconds. In version 10.5.16 my code needs for 26000 records in tmp_tartikel_live 5-6 minutes. It is ok. In version 10.5.18 my code needs for 26000 records in tmp_tartikel_live more than 2 hours and
was terminating by the system and was not ready.
The execution-time glows much more than linear.
The calling script is internal for maintenance-work at night.
The purpose of this code is to build our search-tables in MySQL (concordance). The code must work for strings with special characters in the coding-systems html (è), ansi and utf-8.
In german and france we have the special characters:
    ß
    ü
    ö
    äàá
    èé
    and so on.

I have found other users with performance-problems in MariaDB version 10.5.18, and they also use CONCAT:
 
https://dba.stackexchange.com/questions/284073/query-performance-drop-after-upgrade-to-mariadb-10-5-group-concat-join

My code is the following:
    /*#JODY_20221010
    Die Datenbank muss fuer diesen Code auf Kollektion=latin1_swedish_ci eingestellt sein.
        ALTER DATABASE d03a5b1c COLLATE latin1_swedish_ci;
    Das CHARACTER SET scheint nicht so wichtig zu sein.
    */

    /*
    #JODY_20211228 (ACHTUNG): Diese Datei muss ASCII-Codiert sein (nicht UTF8)         Funktion zum Loeschen von HTML-Tags. Kann nur vom browser aus installiert werden.
    * /
    DROP PROCEDURE IF EXISTS mysql_log;*/
    DROP FUNCTION IF EXISTS mysql_striptags;
    DROP FUNCTION IF EXISTS mysql_replace_utf8_sonderzeichen;
    DROP FUNCTION IF EXISTS mysql_replace_single_char;
    DROP FUNCTION IF EXISTS mysql_replace_char;
    DROP FUNCTION IF EXISTS mysql_replace_umlaute;
    /*DROP FUNCTION IF EXISTS mysql_delete_fuellwoerter;*/

    DELIMITER $$

    /*CREATE PROCEDURE mysql_log(strText VARCHAR(255))
    BEGIN
        INSERT INTO debugout(cText) VALUES (strText);
    END$$*/

    CREATE FUNCTION mysql_striptags(strParam TEXT)
    RETURNS TEXT
    DETERMINISTIC
    BEGIN
        DECLARE str TEXT;
        DECLARE posOpen INT;
        DECLARE posClose INT;

        SET str = strParam;
        loop1: LOOP
            SET posOpen = LOCATE("<", str);
            SET posClose = LOCATE(">", str, posOpen);
                /*#JODY_20211228 Wenn posOpen 0 ist, dann ist posClose auch immer 0.*/
            IF posClose = 0 THEN
                LEAVE loop1;
            END IF;
            SET str = CONCAT(LEFT(str, posOpen - 1), " ", MID(str, posClose + 1));
        END LOOP loop1;
        RETURN str;
    END$$

    /*#JODY_20220201:
    Die Moeglichkeit zur URL-Erzeugung mit UTF8-Sonderzeichen besteht darin, dass ein Anwender Strings     aus einem Eingabefeld in die Zwischenablage kopiert und dann im URL-Feld des Browsers einfuegt.
    Dann stehen in der URL z.B. fuer
        &auml; CONCAT(CHAR(195), CHAR(164))
    Das Problem ist also die Eingabe von Sonderzeichen im URL-Feld des Browsers.*/
    CREATE FUNCTION mysql_replace_utf8_sonderzeichen(strParam TEXT)
    RETURNS TEXT
    DETERMINISTIC
    BEGIN
        DECLARE str TEXT;
        DECLARE nPos INT;
        DECLARE nOrd INT;
        DECLARE strChar VARCHAR(2);

        SET str = strParam;
        SET nPos = 1;
        loop_for: LOOP
            SET nPos = LOCATE(CHAR(195), str, nPos); /*
                ACHTUNG (#JODY_20220201):
                Hier kommen auch Positionen auf ein einfaches a zurueck. Liegt an MySQL. Diese brauche                 ich hier zwar nicht. Aber der Code kann damit umgehen. Durch das LOCATE spare ich mir aber                 fuer die grosse Menge an Zeichen die Schleifendurchlaeufe.*/
            IF nPos = 0 THEN
                LEAVE loop_for;
            END IF;
            SET strChar = MID(str, nPos, 1);
            SET nPos = nPos + 1;
            IF ORD(strChar) != 195 THEN
                ITERATE loop_for;
            END IF;
            SET strChar = MID(str, nPos, 1);
            SET nOrd = ORD(strChar);
            IF nOrd >= 132 AND nOrd <= 188 THEN
                SET str = REPLACE(str, CONCAT(CHAR(195), strChar), CHAR(nOrd + 64));
                SET nPos = nPos + 1;
            END IF;
        END LOOP;

        RETURN str;
    END$$

    /*
    ACHTUNG (#JODY_20220120):
    Da strNewStr auch nur Blanks enthalten darf/kann, kann hier nicht mit CHAR(2) gearbeitet werden.     Variablen vom Typ CHAR(x) waeren bei einem Wert von z.B. " " leer (Laenge 0), da die Laenge sich     aus dem ersten Zeichen von rechts, da kein Blank ist, ergibt. Es sind gewissermassen Fortran-Strings,     die ja auch so arbeiten. VARCHAR sind dagegen C-Strings, die 0-terminiert sind.
    */
    CREATE FUNCTION mysql_replace_single_char(strParam TEXT, nChr INT, strName CHAR(10), strNewStr VARCHAR(2))
    RETURNS TEXT
    DETERMINISTIC
    BEGIN
        DECLARE str TEXT;
        DECLARE strNewStrTmp VARCHAR(2);
        DECLARE strChar195 VARCHAR(2);
        DECLARE nPosEnd INT;

        SET strNewStrTmp = strNewStr;
            /*ACHTUNG (#JODY_20220120): Nach meinem aktuellen Kenntnisstand koennen Parameter nicht geaendert werden.*/
        IF strNewStrTmp = "<" THEN
            SET strNewStrTmp = LEFT(strName, 1);
        END IF;
        SET str = REPLACE(strParam, CONCAT("&", strName, ";"), strNewStrTmp);
        IF nChr <= 255 THEN
            SET str = REPLACE(str, CHAR(nChr), strNewStrTmp);
        END IF;
        SET str = REPLACE(str, CONCAT("&#", CONVERT(nChr, CHAR), ";"), strNewStrTmp);

        RETURN str;
    END$$

    CREATE FUNCTION mysql_replace_char(strParam TEXT, nChrMin INT, nChrMax INT, strNamesExt VARCHAR(40), strNewStr CHAR(1))
    RETURNS TEXT
    DETERMINISTIC
    BEGIN
        DECLARE str TEXT;
        DECLARE nChr INT;
        DECLARE strNames VARCHAR(40);
        DECLARE nPosStart INT;
        DECLARE nPosEnd INT;
        DECLARE bUseNames TINYINT;
        DECLARE strName VARCHAR(40);
        DECLARE strNewStrUpper CHAR(1);

        SET str = strParam;
        SET nChr = nChrMin;

        IF strNamesExt != "" THEN
            /*#JODY_20211229
            In MySQL gibt es in Stored Procedures keine Array-Unterstuetzung.
            s. https://forums.mysql.com/read.php?98,406197,406216*/
            SET strNames = CONCAT("grave;acute;circ;", strNamesExt);
                /*#JODY_20220408 Dieser Code ist fuer die Sonderzeichen &agrave; usw. gedacht. Nicht fuer &grave;*/
            SET bUseNames = 1;
            SET strNewStrUpper = UPPER(strNewStr);
            SET nPosStart = 1;
        ELSE
            SET bUseNames = 0;
        END IF;

        loop_for: LOOP
            IF bUseNames != 0 THEN
                SET nPosEnd = LOCATE(";", strNames, nPosStart);
                SET strName = MID(strNames, nPosStart, nPosEnd - nPosStart + 1);
                    /*#JODY_20211229 Das ; will ich mit haben.*/
                SET str = REPLACE(str, CONCAT("&", strNewStr, strName), strNewStr);                 SET str = REPLACE(str, CONCAT("&", strNewStrUpper, strName), strNewStr);
                /*SET strNames = MID(strNames, nPos + 1);*/
                SET nPosStart = nPosEnd + 1;
                    /*#JODY_20211229 So ersprare ich mir dieses MID.*/
            END IF;

            SET str = REPLACE(str, CONCAT("&#", CONVERT(nChr, CHAR), ";"), strNewStr);
            SET str = REPLACE(str, CHAR(nChr), strNewStr);

            /*#JODY_20211229
            Diese Funktion wird nur fuer Umlaute und nur fuer die kleinen augerufen. Diese liegen zwischen
            &#224; und &#252;.*/
            SET str = REPLACE(str, CONCAT("&#", CONVERT(nChr - 32, CHAR), ";"), strNewStr);
            SET str = REPLACE(str, CHAR(nChr - 32), strNewStr);
            IF nChr >= nChrMax THEN
                LEAVE loop_for;
            END IF;
            SET nChr = nChr + 1;
        END LOOP;

        RETURN str;
    END$$

    CREATE FUNCTION mysql_replace_umlaute(strParam TEXT)
    RETURNS TEXT
    DETERMINISTIC
    BEGIN
        DECLARE str TEXT;
        DECLARE nPos INT;
        DECLARE nChr INT;

        SET str = mysql_replace_utf8_sonderzeichen(strParam); /*
            ACHTUNG (#JODY_20220201):
            Die UTF8-Sonderzeichen muessen hier ganz oben behandelt werden. Sie werden in ASCII-Sonderzeichen             konvertiert, die ja nachfolgend auch noch wieder konvertiert werden. So kann ich das aber allgemein
            gueltig fuer alle UTF8-Sonderzeichen abhandeln.*/

        SET str = REPLACE(LOWER(str), "make-up", "makeup");
            /*#JODY_20220315 Make-Up soll intern als ein Wort behandelt werden.*/

        /*#JODY_20220120
        Die vor- und nachlaufenden Blanks werden benoetigt, damit der
        Wortanfaeng/-ende richtig und leicht erkannt wird.
        */
        SET str = CONCAT(" ", mysql_striptags(str), " ");

        SET str = mysql_replace_char(str, 224, 230, "tilde;uml;ring;elig;", "a");
        SET str = mysql_replace_char(str, 232, 235, "uml;", "e");
        SET str = mysql_replace_char(str, 236, 239, "uml;", "i");
        SET str = mysql_replace_char(str, 242, 246, "tilde;uml;slash;", "o");
        /*#JODY_20211228
            So brauche ich den Ignore-Parameter in mysql_replace_char() nicht mehr.
            &#215; und &#247; sollen hier nicht beachtet werden.*/
        SET str = mysql_replace_single_char(str, 216, "Oslash", "o");
        SET str = mysql_replace_single_char(str, 248, "oslash", "o");
        SET str = mysql_replace_char(str, 249, 252, "uml;", "u");
        SET str = mysql_replace_single_char(str, 223, "szlig", "ss");

        SET str = REPLACE(str, "ae", "a");
        SET str = REPLACE(str, "oe", "o");
        SET str = REPLACE(str, "ue", "u");

        SET str = mysql_replace_single_char(str, 191, "iquest", ""); /*#JODY_20211228 fran&ccedil;ois*/         SET str = mysql_replace_single_char(str, 199, "Ccedil", "<");/*#JODY_20211228 fran&ccedil;ois*/         SET str = mysql_replace_single_char(str, 231, "ccedil", "<");/*#JODY_20211228 fran&ccedil;ois*/         SET str = mysql_replace_single_char(str, 241, "ntilde", "<");/*#JODY_20211228 porte&#241;o*/
        SET str = mysql_replace_single_char(str, 215, "times", "x");
        SET str = mysql_replace_single_char(str, 160, "nbsp", " ");
        SET str = mysql_replace_single_char(str, 178, "sup2", "2");    /*#JODY_20211228 Hochgestellte 2 z.B. bei dem Hersteller dsquared&#178;*/         SET str = mysql_replace_single_char(str, 179, "sup3", "3");    /*#JODY_20211228 Hochgestellte 3 z.B. "wella care&#179; balance clean anti"*/         SET str = mysql_replace_single_char(str, 185, "sup1", "");    /*#JODY_20211228 Hochgestellte 1; wird aber nicht benoetigt.*/         SET str = mysql_replace_single_char(str, 8216, "lsquo", "");/*#JODY_20211228 j&lsquo;adore*/         SET str = mysql_replace_single_char(str, 8217, "rsquo", "");/*#JODY_20211228 j&rsquo;adore*/
        SET str = REPLACE(str, "'", "");        /*#JODY_20211228 l'oreal*/

        SET str = mysql_replace_single_char(str,   34/*"*/, "quot", "");/*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str,  169, "copy", " ");    /*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str,  173, "shy", "");        /*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str,  174, "reg", " ");        /*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str,  176, "deg", " ");        /*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str,  183, "middot", " ");    /*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str, 8194, "ensp", " ");    /*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str, 8218, "sbquo", " ");    /*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str, 8226, "bull", " ");    /*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str, 8230, "hellip", " ");    /*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str, 8364, "euro", "euro");    /*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str, 8482, "trade", " ");    /*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str, 8722, "minus", " ");    /*#JODY_20211228 Ist fuer die Suche nicht relevant.*/
        SET str = REPLACE(str, "&#776;", "");
            /*#JODY_20211228 Beispiel: "ascorbinsaure natu&#776;rliches aroma"; Bei "a&#776;" wird ein &auml; angezeigt.*/

        SET str = mysql_replace_single_char(str, 60, "lt", " ");    /*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str, 62, "gt", " ");    /*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str, 171, "laquo", " ");/*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str, 187, "raquo", " ");/*#JODY_20211228 Ist fuer die Suche nicht relevant.*/         SET str = mysql_replace_single_char(str, 189, "frac12", "");/*#JODY_20211228 "mit ca &frac12; liter"*/

        /*#JODY_20211228 (ACHTUNG):
        Prinzipiell soll &acute; durch ein Blank ersetzt werden.
        Nur bei loreal ist dies auf Grund des Eigennamens nicht erwuenscht.*/         SET str = mysql_replace_single_char(str, 96, "grave", " ");/*#JODY_20220408"*/         /*SET str = REPLACE(str, "l&acute;oreal", "loreal"); #JODY_20220408*/         SET str = mysql_replace_single_char(str, 180, "acute", " ");/*#JODY_20211228 "save&acute;n" oder "rock&acute;n"*/

        SET str = REPLACE(str, "&amp;", " ");

        /*#JODY_20220119 Es exisztieren so viele Begriffe, die in [] eingeklammert sind. z.B. [iln48006]*/
        SET str = REPLACE(str, "[", " ");
        SET str = REPLACE(str, "]", " ");
        SET str = REPLACE(str, "#", " ");
        SET str = REPLACE(str, "*", " ");
        SET str = REPLACE(str, "&", " ");
        SET str = REPLACE(str, "%", " ");
        SET str = REPLACE(str, "|", " ");/*#JODY_20220316*/

        SET str = REPLACE(str, ".", " ");
        SET str = REPLACE(str, ":", " ");
        SET str = REPLACE(str, ",", " ");
        SET str = REPLACE(str, ";", " ");
        SET str = REPLACE(str, "?", " ");
        SET str = REPLACE(str, "!", " ");
        SET str = REPLACE(str, "/", " ");
        SET str = REPLACE(str, "\\", " ");
            /*#JODY_20220120 Macht mir z.B. beim Suchbegriff "wax\" die SQL-Anweisung kaputt.*/
        SET str = REPLACE(str, "-", " ");
        SET str = REPLACE(str, "+", " ");
        SET str = REPLACE(str, "=", " ");
        SET str = REPLACE(str, "\r", " ");
        SET str = REPLACE(str, "\n", " ");
        SET str = REPLACE(str, "\t", " ");

        SET str = REPLACE(str, "(", " ");
        SET str = REPLACE(str, ")", " ");

        /*
        #JODY_20220121
        Erstmal nicht. Die Anwender suchen meistens nach Woertern, wo ein loeschen dieser Buchstaben das         Suchergebnis eigentlich verschlechtert, da weniger Zeichenuebereinstimmungen bei Teilwoertern
        gefunden werden. In Teilwoertern
        #JODY_20220120 Dies soll die Menge der Wortredundanzen verringern. z.B. zugewandte/zugewandt* /
        SET str = REPLACE(str, "em ", " ");
        SET str = REPLACE(str, "en ", " ");
        SET str = REPLACE(str, "es ", " ");
        SET str = REPLACE(str, "er ", " ");
        SET str = REPLACE(str, " sie ", " ");
            /*#JODY_20220120
            Dies ist so noetig, da "sie" durch das naechste REPLACE zu "si" wird und eine Gleichbehandlung             von "sie" und "si" wegen der vielen Suchen nach "si" nicht erwunescht ist. Ausserdem macht die
            Suche nach "sie" eigentlich auch keinen Sinn.* /
        SET str = REPLACE(str, "e ", " ");
        SET str = REPLACE(str, "ig ", " ");*/

        /*#JODY_20211229 Bisher koennen durchaus mehrere Leerzeichen hintereinander sein. Diese jetzt zu einem zusammenstreichen.*/
        loop1: LOOP
            SET nPos = LOCATE("  ", str);
            IF nPos = 0 THEN
                LEAVE loop1;
            END IF;
            SET str = REPLACE(str, "  ", " ");
        END LOOP loop1;

        SET str = TRIM(str);
            /*#JODY_20220120
            Die vor- und nachlaufenden Blanks wieder loeschen. Wurde nur eingefuegt,
            damit der Wortanfaeng/-ende richtig und leicht erkannt wird.
            */

        RETURN str;
    END$$

    DELIMITER ;
    CREATE TABLE tmp_tartikel_live (
        kArtikel            INT UNSIGNED,
        cArtNr                VARCHAR(31),
        cSeo                VARCHAR(255),
        cSeoU                TEXT,
        cBeschreibung        TEXT,
        cBeschreibungU        TEXT,
        cName                VARCHAR(255),
        cSuchbegriffe        TEXT,
        cKurzBeschreibung    TEXT,
        kurztyp                TEXT,
        kurzserie            TEXT,
        kurzname            TEXT
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
    SELECT
        tmp_tartikel_live.kArtikel,
        tmp_tartikel_live.cArtNr,
        tmp_tartikel_live.cSeo,
        tmp_tartikel_live.cBeschreibung,
        CONCAT(" ", mysql_replace_umlaute(tmp_tartikel_live.cName), " ") AS cNameU,         CONCAT(" ", mysql_replace_umlaute(tmp_tartikel_live.cSuchbegriffe), " ") AS cSuchbegriffeU,         CONCAT(" ", mysql_replace_umlaute(tmp_tartikel_live.cKurzBeschreibung), " ") AS cKurzBeschreibungU,         CONCAT(" ", mysql_replace_umlaute(tmp_tartikel_live.cBeschreibung), " ") AS cBeschreibungU,         CONCAT(" ", mysql_replace_umlaute(tmp_tartikel_live.cSeo), " ") AS cSeoU,         CONCAT(" ", mysql_replace_umlaute(tmp_tartikel_live.kurztyp), " ") AS kurztypU,         CONCAT(" ", mysql_replace_umlaute(tmp_tartikel_live.kurzserie), " ") AS kurzserieU,         CONCAT(" ", mysql_replace_umlaute(tmp_tartikel_live.kurzname), " ") AS kurznameU
    FROM tmp_tartikel_live

This code prepare article-text for search in. Is this problem known or is it new.

I hope, I do it right in this way.

Johannes Ody


_______________________________________________
Mailing list: https://launchpad.net/~maria-discuss
Post to     : maria-discuss@lists.launchpad.net
Unsubscribe : https://launchpad.net/~maria-discuss
More help   : https://help.launchpad.net/ListHelp

Reply via email to