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
ä 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@lists.launchpad.net
Unsubscribe : https://launchpad.net/~maria-discuss
More help : https://help.launchpad.net/ListHelp