← Back to team overview

maria-discuss team mailing list archive

Re: MariaDB 10.5.18: Performance-Problems with CONCAT

 

> Op 4 jan. 2023 om 16:12 heeft Johannes Ody <j.ody@xxxxxxxxxxxxx> het volgende geschreven:
> 
> 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).

Are you hit by MDEV-29988?

> 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 (&egrave;), ansi and utf-8.
> In german and france we have the special characters:
>     &szlig;
>     &uuml;
>     &ouml;
>     &auml;&agrave;&aacute;
>     &egrave;&eacute;
>     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@xxxxxxxxxxxxxxxxxxx
> Unsubscribe : https://launchpad.net/~maria-discuss
> More help   : https://help.launchpad.net/ListHelp



Follow ups

References