maria-discuss team mailing list archive
-
maria-discuss team
-
Mailing list archive
-
Message #06476
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 (è), 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
> ä 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 à usw. gedacht. Nicht fuer `*/
> 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
> à und ü.*/
> 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.
> × und ÷ 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çois*/
> SET str = mysql_replace_single_char(str, 199, "Ccedil", "<");/*#JODY_20211228 françois*/
> SET str = mysql_replace_single_char(str, 231, "ccedil", "<");/*#JODY_20211228 françois*/
> SET str = mysql_replace_single_char(str, 241, "ntilde", "<");/*#JODY_20211228 porteñ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²*/
> SET str = mysql_replace_single_char(str, 179, "sup3", "3"); /*#JODY_20211228 Hochgestellte 3 z.B. "wella care³ 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‘adore*/
> SET str = mysql_replace_single_char(str, 8217, "rsquo", "");/*#JODY_20211228 j’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, "̈", "");
> /*#JODY_20211228 Beispiel: "ascorbinsaure natürliches aroma"; Bei "ä" wird ein ä 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 ½ liter"*/
>
> /*#JODY_20211228 (ACHTUNG):
> Prinzipiell soll ´ 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´oreal", "loreal"); #JODY_20220408*/
> SET str = mysql_replace_single_char(str, 180, "acute", " ");/*#JODY_20211228 "save´n" oder "rock´n"*/
>
> SET str = REPLACE(str, "&", " ");
>
> /*#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