Beiträge von info@biketeile-service.de

    templates/<template_name>/module/product_navigation/products_page_navigation.html

    Code
    <div class="col-xs-6 text-right pt5">
        [COLOR='#FF0000']{$COUNT}[/COLOR]
    </div>


    advanced_search_result.php schreibt darein nichts, obwohl den passenden Wert dafür hat. Somit erscheint übliches "Zeige 1 bis 20 (von insgesamt 2031 Produkten)" nicht.
    advanced_search_result.php, line 324

    Code
    $navigation_smarty->assign('LINKS', $page_links);
    $navigation_smarty->assign('language', $_SESSION['language']);


    $navigation_smarty->assign('COUNT', $page_links['total']); gehört noch dazu...

    includes/classes/class.navigation.php, function view_per_site

    Code
    if ($site == 'new_products' || $site == 'specials' || $site == 'product_listing') {
    $nav_parms = xtc_get_all_get_params(array('products_id', 'x', 'y', 'cat', 'per_site', 'multisort', 'filter_id', 'page', 'view_as'));
    [COLOR='#FF0000']$file_name = $file_name;[/COLOR]


    Tiefere Bedeutung...
    Der Code, der diese Klasse benutzt (z.B advanced_search_result.php), setzt $file_Name-Variable. Hat man "global $file_name" gemeint?

    Code
    $view_per_site = ($per_site == 9 ? '<b>9</b>' : '<a rel="nofollow" href="' . xtc_href_link($file_name, $nav_parms . 'per_site=9' . [COLOR='#FF0000']$get_param[/COLOR]) . '">9</a>') . ' | ';


    Auch global?

    Die Perfomance-Probleme zeigen sich erst, wenn man relativ große Anzahl Kategorien/Produkte im Shop hat. Bei mir sind ca. 2 000 000 Produkte. Der Shop wird bei solcher Menge dramatisch langsam und instabil. Die Response-Zeit (wenn überhaupt eine Antwort kommt) kann über eine Minute sein (je nach Shopbereich). Es gibt jedoch das Potenzial ihn zu beschleunigen. Dafür muss man evtl. tief in die Engine-Logik angreifen.

    Ich möchte erst die beiden Andreas fragen: Habt ihr Interesse daran? Oder schließen wir das Thema sofort ab, wenn ihr meint, dass das angebotene System seine Grenzen hat und meine Anforderungen einfach außerhalb liegen?

    Der nachstehende Link ist der erste in Serie. Und je nach Antwort kann auch der letzte sein. :)
    http://plussupport.commerce-seo.de/showthread.php?t=2456

    includes/classes/class.split_page_results.php, line 127

    Code
    $count_query = xtDBquery($query);
    $count = xtc_db_num_rows($count_query, true);


    $query beinhaltet die komplette Abfrage mit ORDER BY Klausel. Fürs Zählen ist die Sortierung absolut irrelevant und nimmt wahnsinnig viel Zeit (Der/Die Index/Indizes wird/werden für Sortierung wegen Abfrage-Struktur nicht verwendet. Das ist aber ein anderes Thema).

    Weiterhin werden alle Spalten, welche in der Abfrage angegeben sind (z.B. p.*, pd.products_name, pd.products_description, pd.products_short_description), durch MySql-Server für die Ausgabe bereitgestellt. Sie werden dann verworfen, weil wir nur Anzahl brauchen, aber der Server hat dafür mutig gearbeitet. Die meisten Spalten kommen in die Suchkriterien gar nicht, somit fressen sie einfach Speicher.

    Der Code zwischen Zeile 100 und 124 inkl. stellt die Leiche von irgendeiner Vorversion bzw. irgendeinem Vorversuch dar. Tut nichts.

    Siehe auch http://plussupport.commerce-seo.de/showthread.php?t=2457

    includes/classes/class.split_page_results.php, line 161 und überall in dieser Datei, wo man code reuse nicht versteht.

    Code
    $start = $this->current_page_number - $max_page_links;
    $start = $start < 1 ? 1 : $start;
    
    
    $end = $this->current_page_number + $max_page_links;
    $end = $end > $this->number_of_pages ? $this->number_of_pages : $end;


    Die Logik in diesem Auszug kann ich nicht kapieren. Sie produziert als Beispiel Folgendes, wobei in Max-Werte-Einstellungen nur 5 für Blättern angegeben ist:
    [ATTACH=CONFIG]767[/ATTACH]

    So ist besser (IMHO)

    Code
    $start = $this->current_page_number - (int)($max_page_links / 2);
    $start = $start < 1 ? 1 : $start;
    
    
    $end = $start + $max_page_links - 1;
    if ($end > $this->number_of_pages) {
        $end = $this->number_of_pages;
        $start = $end - $max_page_links + 1;
        $start = $start < 1 ? 1 : $start;
    }

    includes/modules/product_listing.php, line 129
    "Kategoriebeschreibung beim blaettern raus". Warum? Oder besser gefragt: In wie fern unterscheidet sich die erste Seite von den anderen, dass man die Beschreibung anzeigt?

    Code
    //Kategoriebeschreibung beim blaettern raus
    if (!isset($_GET['page']) || $_GET['page'] == '1') {
        $module_smarty->assign('CATEGORIES_DESCRIPTION', $category['categories_description']);
        $module_smarty->assign('CATEGORIES_DESCRIPTION_FOOTER', $category['categories_description_footer']);
    }

    inc/commerce_seo.inc_orig.php, from line 590
    createSeoDBTableProduct

    6.

    Code
    while ($productList = xtc_db_fetch_array($product_query)) {
        ...
        if ($useLanguageUrl) {
            $lang_query = xtc_db_fetch_array(xtDBquery("SELECT code FROM " . TABLE_LANGUAGES . " WHERE languages_id = '" . $productList['language_id'] . "'"));
        ...
    }


    Unnötige Abfrage wird pro Produkt pro Sprache durchgeführt. Die Sprachen bleiben während der SEO-Linkgenerierung konstant.

    7.

    Code
    $doppel_query = xtc_db_query("SELECT COUNT(products_name) AS counter  FROM " . TABLE_PRODUCTS_DESCRIPTION . " WHERE products_name='" . $productListname . "'");
    $doppel_id = xtc_db_fetch_array($doppel_query);
    if ($doppel_id['counter'] > 1) {


    Wenn es auf Anzahl größer eins verglichen wird, wozu MySql dazu zwingen, alle Treffer aufzuzählen? Es reicht doch nur die erste zwei finden:

    Code
    $doppel_query = xtc_db_query("SELECT products_id FROM " . TABLE_PRODUCTS_DESCRIPTION . " WHERE products_name='" . $productListname . "' LIMIT 2");
    if (xtc_db_num_rows($doppel_query, false) > 1) {

    8. line 364, getCategoryPathForProduct
    Der größte Zeitverlust geschieht in dieser Methode. Sie braucht das komplette Reengineering.

    Zahlen:
    Anzahl Produkten: 1921013
    Anzahl Sprachen: 2
    SEO-Modul Einstellungen:

    Sprachabhängige URLs
    ../de/.. | ../en/..
    True

    Kurze URLs?
    False

    Lange URL auf Kurze URL umleiten?
    True

    URL in Kleinbuchstaben?
    True

    SEO Suchwörter?
    False

    404 oder 410?
    True

    Doppelten Content vermeiden
    True

    Doppelte Namen vermeiden
    True

    Anzahl Produkten pro Durchlauf: 5000

    Nach dem beseitigen des "Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 72bytes)"-Fehlers (Ich musste Limit auf 4 GB hochsetzen), habe ich die Durchlauf-Ausführungszeit aufgenommen.
    Mittelwert: 254.72 Sek.
    Nach dem Reengineering anhand der Punkte 1 bis 8:
    Mittelwert: 11.07 Sek mit 256 MB Memory Limit.

    So, Optimierungsbedarf.

    admin/includes/modules/cseo/commerce_seo_url.php, from line 105

    1. Jeder Scriptaufruf holt alle product_id aus products_description. Danach wird pagination durchgeführt ("for ($i = $offset; $i <= $limit; $i++)"). Überlasse doch diese Aufgabe an MySql-Server:
    http://dev.mysql.com/doc/refman/5.6…timization.html
    "SELECT products_id FROM " . TABLE_PRODUCTS_DESCRIPTION . " ORDER BY products_id LIMIT $offset, $step"
    Für ORDER BY products_id wird ein Index für "products_id"-Spalte benötigt.

    2. Die Tabelle products_description enthält Lokalisierungen für alle Sprachen, somit kommen ins Abfrageergebnis alle products_id mal Anzahl Sprachen. Später in inc/commerce_seo.inc.php, line 599 werden sowieso alle lokalisierte Namen abgefragt.

    Code
    $product_query = xtDBquery("SELECT
        products_id,
        language_id,
        products_name,
        products_url_alias,
        url_old_text
        FROM
        " . TABLE_PRODUCTS_DESCRIPTION . "
        WHERE products_id=" . $productID);


    Es ergibt sich, dass jedes Produkt genau so viel mal abgearbeitet wird, wie die Anzahl Sprachen. Denkbar wäre noch DISCTINCT dazu:
    "SELECT DISTINCT products_id FROM " . TABLE_PRODUCTS_DESCRIPTION . " ORDER BY products_id LIMIT $offset, $step"

    3.

    Code
    while ($pID = xtc_db_fetch_array($pQuery))
        $pA[] = $pID['products_id'];


    OK. Das ist klar. Aber

    Code
    for ($k = 0; $k <= sizeof($pA); $k++)
        $pHash[] = array('pid' => $pA[$k]);


    ist Murks. $pHash[] wird nur einmal verwendet und zwar da: $commerceSeo->createSeoDBTableProduct($i, $pHash[$i]['pid']);
    Was ist das? Ein Array befüllen, ins andere die Werte drüberschaufeln und das letzte nutzen. Könnte man nicht von Anfang an das erste nutzen? Speicherverschwendung, CPU-Zeitverschwendung und das Script tut so, als es was sehr wichtiges zu tun hätte.

    4. admin/includes/modules/cseo/commerce_seo_url.php, from line 156

    Code
    $selbstaufruf = '<script language="javascript" type="text/javascript">setTimeout("document.img_continue.submit()", 3000);</script>';


    Worauf warten wir drei Sekunden?

    5. Auf dem Frontend wird nur Zähler geändert. Um die Änderung davon anzuzeigen wird aber die komplette Seite übertragen. Ajax doch mal!

    Zitat

    Achja sorry was ich weiss, wen man ein eigene separate index.html hat kan man die nur benutzen wen es ausgeklammert ist

    Es ist bloß das selbe wie "die folgenden beiden Zeilen auskommentieren wenn Sie eine index.html nutzen wollen". Was sich dahinten steckt, ist unklar.

    Zitat

    Wen nicht ist alles mit start auf den root und kein index.php aber so umgeschrieben, dass es eben den root ist, was teils beim mehrere sprachen dan auch manchmal ein problem gegeben hat mit den /de/, /de oder / beim ein par versionen und updates, anpassungen mit den startseite hauptsprache

    Sorry, aber diese Information ist genau so informativ wie keine.

    Zitat

    kein wirklich supported updates davon

    Das Xajax-Projekt ist open source und kostenlos. Support, welcher die Entwickler anbieten, ist fürs solche Geschäft angemessen.

    Zitat

    Wen da ein vernünftiger weiter entwickelung

    Shop nutzt Version 0.2.5, aktuelle Version ist 0.5.

    Zitat

    kein support drauf und sehr alt

    Letzter Commit war vor 10 Tage. Das Projekt lebt und lebt wohl. https://github.com/Xajax/Xajax
    Es ist mir egal, wenn commerce:seo eine alte Version bevorzugt. Wichtig ist, dass es richtig funktioniert und der Entwickler weiß, was er tut.

    1. .htaccess, line 233

    Apache Configuration
    # immer auf den root verweisen, damit die Startseite (/index.php) nicht zweimal vorkommt
    # die folgenden beiden Zeilen auskommentieren wenn Sie eine index.html nutzen wollen
    RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.(html?|php)\ HTTP/
    RewriteRule ^index\.(html?|php)$ http://%{HTTP_HOST}/ [R=301,L]


    Was macht genau diese Regel? Was ist das Ziel davon? Aus der Beschreibung kann ich leider nichts verstehen. Ich frage deswegen, weil diese Regel standardmäßig aktiv ist und ein Problem bei der Suche verursacht (siehe nächsten Punkt).

    2. includes/xajax/xajax.cseofunctions.php, line 21

    Code
    $xajax->setRequestURI($_SERVER['PHP_SELF']);


    Gibt es da einen geheimen Grund, warum der URI ständig umgeschrieben wird?
    Irgendwann, wenn man die Hauptseite des Shops abruft (z.B. durch Eingeben des Domainnamen), wird index.php ausgeführt. URI für xajax-Calls wird auf /index.php gesetzt. Versucht man jetzt ins Suche-Eingabefeld was einzutippen, bekommt man keine Suchvorschläge. Was passiert: xajax generiert auf der Client-Seite einen POST-Request auf http://www.myshop.de/index.php. Durch die o. g. RewriteRule wird dieser Request mit dem HTTP-Code 301 (Moved permanently) auf http://www.myshop.de/ umgeleitet. Der Browser macht einen weiteren Request auf die neue Location, in diesem Fall aber GET-Request. Und die Parameter, die mit POST angehängt wurden, gehen verloren. Der wichtige Parameter "xajax", welcher den Name der auf der Server-Seite aufzurufenden Methode beinhaltet, ist weder in $_POST noch in $_GET vorhanden. xajax tut nichts und zurück wird die komplette Seite (html mit allem drum und dran) geliefert.

    3. includes/xajax/xajax_core/xajax.inc.php, line 511

    Code
    @unlink($cache_file);
    file_put_contents($cache_file, $c.$html);


    Der Code wird bei jedem Zugriff ausgeführt. Cache-Datei wird somit pro Client pro Zugriff gelöscht und neu geschrieben. Race condition unvermeidlich.

    4. includes/xajax/xajax_core/xajax.inc.php und includes/xajax/xajax_core/xajax_checkout.inc.php sind absolut identisch bis auf die Zeile 496. Code reuse war unmöglich?

    Zum Thema Suchfunktion:

    Durch die fehlerhafte Abfrage greift die erweiterte Suche (advanced_search_result.php) auf fehlertolerante Suche (includes/classes/class.fuzzy_search.php) zurück.
    Falls fehlertolerante Suche deaktiviert ist, wird nichts gefunden.

    advanced_search_result.php, line 161

    Code
    $from_str = " FROM " . TABLE_PRODUCTS . " AS p
    	JOIN " . TABLE_SPECIALS . " AS s ON (p.products_id = s.products_id)


    In MySql JOIN == INNER JOIN. Somit filtert "products JOIN specials" alle Produkte, für welche keine Sonderangebote konfiguriert sind, aus den möglichen Treffer weg.

    Diejenige, die nur ein Paar Kategorien im Shop haben, können ruhig dieses Thema auslassen.

    Im Shop etwa 10000 Kategorien insgesamt. templates/v2next-boot-flat/source/boxes/cat_nav.ph wird bei relativ größerer Kategorienanzahl einfach Perfomance-Killer. Mit der Kategorien im Navigationsbereich ist es mir nie gelungen, den Antwort von Shop zu bekommen. Einfach down.

    1. line 324 in xtc_show_category_superfish method

    Code
    // Unterkategorien durchsteppen
    foreach ($foo as $key => $value) {
        if ($foo[$key]['parent'] == $cid) {
            ...
            xtc_show_category_superfish($key, $level + 1, $foo, ($level != 0 ? $cpath . $cid . '_' : ''));


    Erstens, im Falle, dass alle Kategorien irgendeinen Parent haben (mein Fall), wird xtc_show_category_superfish für jede Unterkategorie rekursiv aufgerufen. Gesamte Iterationenanzahl liegt etwa bei 10000 * 10000 = 100000000.
    Zweitens, man hat bereits ein Array $foo[$cat_id]['subcats'], wo alle Unterkategorien aufgelistet sind.

    2. line 494 in initCategoryLink method

    Code
    $CategoryLink = xtc_href_link(FILENAME_DEFAULT, xtc_category_link(intval($CatID), $CatName));


    Beim Aufruf von xtc_category_link wird intern die Methode xtc_get_parent_categories aufgerufen. Da ist der Code davon:


    Je nach Tiefe von Kategorienbaum kommen Zehntausende Zugriffe auf die Datenbank.

    Es gibt bestimmt noch weitere Punkte. Keine Lust zu analysieren. Das Prinzip von Darstellen der Kategorien im Navigationsbereich ist einfach falsch. Wozu muss man ALLE Kategorien zum User drüber schaufeln? To Admin: Werfe einen Blick in Kategorienbox. Dort ist es richtig. Schlüsselwort: "on demand" und für Navigationsbereich zusäzlich noch "ajax".