Autor Zpráva
ales_naprstek
Profil
Prosím o radu s pomalým SQL dotazem, jedná se o výběr produktů z eshopu. Bohužel se databáze rozrostla a eshop obsahuje trošku více produktů. Zkoušel jsem několik úprav, ale žádná mne nedovedla ke zlepšení času. Dotaz, počty záznamů a strukturu tabulek uvádím pod problémovým selectem.

Předem velmi děkuji za jakoukoliv pomoc.



# Query_time: 6.127047  Lock_time: 0.000253 Rows_sent: 15  Rows_examined: 1123184
SET timestamp=1598802021;
SELECT p.id_produkt
FROM   t_e_produkty AS p
       INNER JOIN (SELECT DISTINCT kp.id_produkt
                   FROM   t_e_vazba_katprod AS kp
                          INNER JOIN t_e_kategorie AS k
                                  ON kp.id_e_kategorie = k.id_e_kategorie
                   WHERE  k.lft >= 1
                          AND k.rft <= 2022) t
               ON p.id_produkt = t.id_produkt
WHERE  p.zobrazovat = 'A'
       AND p.platny = 'A'
ORDER  BY p.d_zobrazovat_od DESC
LIMIT  0, 15;

Tabulka t_e_produkty obsahuje 281 934 řádků.
Tabulka t_e_kategorie obsahuje 1 504 řádků.
A vazební tabulka t_e_vazba_katprod obsahuje 296 702 řádků.


Struktura je následující:

CREATE TABLE `t_e_kategorie` (
  `id_e_kategorie` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
  `nazev_cz` varchar(80) CHARACTER SET utf8 DEFAULT NULL,
  `popis_cz` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
  `nazev_en` varchar(80) CHARACTER SET utf8 DEFAULT NULL,
  `popis_en` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
  `nazev_de` varchar(80) CHARACTER SET utf8 DEFAULT NULL,
  `popis_de` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
  `id_e_kat_rodic` smallint(5) unsigned NOT NULL DEFAULT '0',
  `poradi` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `lft` smallint(5) unsigned NOT NULL DEFAULT '0',
  `rft` smallint(5) unsigned NOT NULL DEFAULT '0',
  `pocet_polozek` int(10) NOT NULL DEFAULT '0',
  `pocet_akci` int(10) NOT NULL DEFAULT '0',
  `pocet_doporucujeme` int(10) DEFAULT '0',
  `cesta_gen_cz` text CHARACTER SET utf8,
  `cesta_gen_en` text CHARACTER SET utf8,
  `cesta_gen_de` text CHARACTER SET utf8,
  `platny` enum('A','N') CHARACTER SET utf8 NOT NULL DEFAULT 'A',
  PRIMARY KEY (`id_e_kategorie`),
  KEY `idx_lft` (`lft`),
  KEY `idx_rft` (`rft`),
  KEY `idx_id_e_kat_rodic` (`id_e_kat_rodic`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;


CREATE TABLE `t_e_produkty` (
  `id_produkt` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id_kvalita` tinyint(3) unsigned DEFAULT NULL,
  `id_dodavatel` smallint(5) unsigned DEFAULT NULL,
  `d_vlozeni` datetime DEFAULT NULL,
  `d_zobrazovat_od` datetime DEFAULT NULL COMMENT 'od kdy se ma zobrazovat na hlavni strance',
  `pocet_obrazku` smallint(5) unsigned DEFAULT '0' COMMENT 'na tohle je trigger na t_obrazky',
  `provize` tinyint(3) unsigned DEFAULT NULL,
  `nazev_cz` varchar(255) DEFAULT NULL,
  `nazev_en` varchar(255) DEFAULT NULL,
  `nazev_de` varchar(255) DEFAULT NULL,
  `popis_cz` text,
  `popis_en` text,
  `popis_de` text,
  `hmotnost` smallint(5) unsigned DEFAULT NULL,
  `cena` int(10) DEFAULT NULL,
  `doporucujeme` enum('A','N') DEFAULT 'N',
  `d_doporucujeme` date DEFAULT NULL,
  `neprehlednete` enum('A','N') DEFAULT 'N',
  `akce` enum('A','N') DEFAULT 'N' COMMENT 'uz se nepouziva',
  `cena_akce` int(10) unsigned DEFAULT NULL COMMENT 'uz se nepouziva',
  `sleva_akce` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `d_akce_od` date DEFAULT NULL,
  `d_akce_do` date DEFAULT NULL,
  `na_objednavku` enum('A','N') DEFAULT 'N',
  `pocet_skladem` smallint(5) unsigned DEFAULT '1',
  `prodano` enum('A','N') DEFAULT 'N' COMMENT 'nepouziva se a asi ani nebude',
  `dat_prodano` date DEFAULT NULL COMMENT 'nepouziva se a asi ani nebude',
  `vyuctovano` enum('A','N') DEFAULT 'N',
  `pocet_zobrazeni` int(11) NOT NULL DEFAULT '0',
  `zobrazovat` enum('A','N') NOT NULL DEFAULT 'A',
  `platny` enum('A','N') DEFAULT 'A' COMMENT 'pouziva se pro zkopirovane do akce',
  `vraceno` enum('A','N') DEFAULT 'N' COMMENT 'neprodano, vraceno dodavateli',
  `dt_vraceno` date DEFAULT NULL,
  PRIMARY KEY (`id_produkt`),
  KEY `idx_akce` (`akce`),
  KEY `idx_katalog` (`katalogove_cislo`),
  KEY `idx_cena` (`cena`),
  KEY `idx_doporucujeme` (`doporucujeme`),
  KEY `idx_nazev` (`nazev_cz`),
  KEY `id_dodavatel` (`id_dodavatel`),
  KEY `zobrazovat` (`zobrazovat`),
  KEY `idx_d_akce_od` (`d_akce_od`),
  KEY `idx_d_akce_do` (`d_akce_do`),
  KEY `idx_neprehlednete` (`neprehlednete`),
  KEY `idx_platny` (`platny`),
  KEY `idx_d_zobrazovat_od` (`d_zobrazovat_od`),
  KEY `zobrazovat_platny` (`zobrazovat`,`platny`),
  FULLTEXT KEY `idx_flt_nazev` (`nazev_cz`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


CREATE TABLE `t_e_vazba_katprod` (
  `id_produkt` int(11) DEFAULT NULL,
  `id_e_kategorie` int(11) DEFAULT NULL,
  UNIQUE KEY `vazba` (`id_produkt`,`id_e_kategorie`),
  KEY `vazba2` (`id_e_kategorie`,`id_produkt`)
) ENGINE=MyISAM DEFAULT C
Kajman
Profil
Pro podmínku k.lft >= 1 AND k.rft <= 2022 by se hodil r-tree index. V mysql tak fungují spatial indexy nad geometrickými daty.
explainextended.com/2009/09/29/adjacency-list-vs-nested-sets-mysql

Případně u verzí mysql podporující rekurzi, zkusit pro omezení stromu použít ji.
mariadb.com/kb/en/recursive-common-table-expressions-overview

Dále bych zkusil pro porovnání rychlostí a explainů:
- napsat dotaz i do jednoho joinu bez poddotazu
- zapoznámkovat podmínky na p.zobrazovat a p.platny (pokud podmínku splňují skoro všechy řádky, někdy pomůže tyto podmínky dát v mysql do having části)

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0