快速加入包含密钥表的大数据表

时间:2014-04-26 18:04:09

标签: php mysql sql

这是我的第二个问题,请耐心等待:)

我有一个MySQL数据库,其中包含一个具有以下结构的大表(dati):

CREATE TABLE IF NOT EXISTS `dati` (
  `i1` varchar(200) COLLATE utf8_swedish_ci DEFAULT NULL,
  `i2` varchar(200) COLLATE utf8_swedish_ci DEFAULT NULL,
  `i3` varchar(200) COLLATE utf8_swedish_ci DEFAULT NULL,
  `i4` varchar(200) COLLATE utf8_swedish_ci DEFAULT NULL,
  `i5` varchar(200) COLLATE utf8_swedish_ci DEFAULT NULL,
  `i6` varchar(200) COLLATE utf8_swedish_ci DEFAULT NULL,
  `i7` varchar(200) COLLATE utf8_swedish_ci DEFAULT NULL,
  `i8` varchar(200) COLLATE utf8_swedish_ci DEFAULT NULL,
  `i9` varchar(200) COLLATE utf8_swedish_ci DEFAULT NULL,
  `i10` varchar(200) COLLATE utf8_swedish_ci DEFAULT NULL,
  `totale` double DEFAULT NULL,
  `valore` double DEFAULT NULL,
  KEY `i1` (`i1`(20),`i2`(20),`i3`(20),`i4`(20)),
  KEY `i1_2` (`i1`),
  KEY `i2` (`i2`),
  KEY `i3` (`i3`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci;

以及几个较小的表i1 - i4,其中字段valore中的值与datai<n>中的值相关联,具有以下结构:< / p>

CREATE TABLE IF NOT EXISTS `i1` (
  `livello` varchar(100) COLLATE utf8_swedish_ci DEFAULT NULL,
  `valore` varchar(100) COLLATE utf8_swedish_ci DEFAULT NULL,
  `ordine` double DEFAULT NULL,
  `colore` double DEFAULT NULL,
  `mostrare` double DEFAULT NULL,
  KEY `livello` (`livello`),
  KEY `valore` (`valore`),
  KEY `ordine` (`ordine`),
  KEY `mostrare` (`mostrare`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci;

CREATE TABLE IF NOT EXISTS `i2` (
  `livello` varchar(100) COLLATE utf8_swedish_ci DEFAULT NULL,
  `valore` varchar(100) COLLATE utf8_swedish_ci DEFAULT NULL,
  `ordine` double DEFAULT NULL,
  `colore` double DEFAULT NULL,
  `mostrare` double DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci;

CREATE TABLE IF NOT EXISTS `i3` (
  `livello` varchar(100) COLLATE utf8_swedish_ci DEFAULT NULL,
  `valore` varchar(100) COLLATE utf8_swedish_ci DEFAULT NULL,
  `ordine` double DEFAULT NULL,
  `colore` double DEFAULT NULL,
  `mostrare` double DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci;

CREATE TABLE IF NOT EXISTS `i4` (
  `livello` varchar(100) COLLATE utf8_swedish_ci DEFAULT NULL,
  `valore` varchar(100) COLLATE utf8_swedish_ci DEFAULT NULL,
  `ordine` double DEFAULT NULL,
  `colore` double DEFAULT NULL,
  `mostrare` double DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci;

对于每个i1-14我都有用户做出的选择,并与用户对其允许值的权限合并,PHP会以下列形式生成查询:

SELECT * FROM `dati`
WHERE (`i1` = 'TARGET|TOTALE')
AND (`i2` = 'BANCHE|ADV AWARENESS SPONTANEA OFFLINE')
AND (`i3` = 'BRAND BANCARI|(NET) BANCOPOSTA')
AND (`i4` = 'ANNO|2014' OR `i4` = 'ANNO|2013')

我的问题是我需要所有组合键的值,即使那些在主数据表中没有条目的组合。

我被建议使用i1-i4表的LEFT JOIN将获得所有条目,但我尝试了很多方法并且总是得到错误或非常慢或永不结束查询。如何快速加入dati i1 - i4,以便所有(选定的)组合键出现(即使没有条目在dati中)。

所以我需要加入dati.i1 = i1.valore,dati.i2 = i2.valore等。

感谢您的帮助。 (P.S我几个小时都不会这样做,现在是晚上,晚上会从家里回来)

修改

现在在家里,我会尝试发布一些可能有帮助的例子。

这是一个客户端脚本的查询,适应这些表的名称,我不知道他们为什么这样做,它似乎以某种方式工作,虽然它看起来过于复杂,我不得不生成它PHP动态:

select k.i4 , k.i3, k.i1, k.i2, dati.valore, dati.totale as totale, s.base
from (( select * from (
select valore as i4, ordine as ordine_i4 from i4 where valore in ('ANNO|2013','ANNO|2014')) p,
(select valore as i3, ordine as ordine_i3 from i3 where valore in ('BRAND BANCARI|(NET) BANCOPOSTA','BRAND BANCARI|(NET) CONTO ARANCIO/ING DIRECT','BRAND BANCARI|(NET) GRUPPO UNICREDIT','BRAND BANCARI|BANCA MEDIOLANUM')) b,
(select valore as i1, ordine as ordine_i1 from i1 where valore in ('TARGET|INTERNAUTI','TARGET|INTERNAUTI SOCIAL')) t,
(select valore as i2, ordine as ordine_i2 from i2 where valore in ('BANCHE|ADV AWARENESS ONLINE TOTALE','BANCHE|BRAND AWARENESS TOM','BANCHE|BRAND AWARENESS TOTALE','BANCHE|BRAND AWARENESS TOTALE SPONTANEA','BANCHE|NOTIZIABILITA\' OFFLINE','BANCHE|NOTIZIABILITA\' OFFLINE + ONLINE','BANCHE|NOTIZIABILITA\' ONLINE')) a
 ) k left JOIN (
 select * from dati where i4 in ('ANNO|2013','ANNO|2014') And i3 in ('BRAND BANCARI|(NET) BANCOPOSTA','BRAND BANCARI|(NET) CONTO ARANCIO/ING DIRECT','BRAND BANCARI|(NET) GRUPPO UNICREDIT','BRAND BANCARI|BANCA MEDIOLANUM') And i1 in ('TARGET|INTERNAUTI','TARGET|INTERNAUTI SOCIAL') And i2 in ('BANCHE|ADV AWARENESS ONLINE TOTALE','BANCHE|BRAND AWARENESS TOM','BANCHE|BRAND AWARENESS TOTALE','BANCHE|BRAND AWARENESS TOTALE SPONTANEA','BANCHE|NOTIZIABILITA\' OFFLINE','BANCHE|NOTIZIABILITA\' OFFLINE + ONLINE','BANCHE|NOTIZIABILITA\' ONLINE')) as dati
on k.i4=dati.i4 and k.i3=dati.i3 and k.i1=dati.i1 and k.i2=dati.i2 ) left JOIN (select i4, i1, i2, valore as base from dati where i1='TOTALE' ) s on k.i4=s.i4 and k.i1=s.i1 and k.i2=s.i2 ORDER BY k.ordine_i3, k.ordine_i4, k.ordine_i2, k.ordine_i1

我的一些 NOT WORKING 试验。这在某处有明显的错误,但我似乎无法解决它

((SELECT * FROM `dati`
    WHERE (`i1` = 'TARGET|TOTALE')
    AND (`i2` = 'BANCHE|ADV AWARENESS SPONTANEA OFFLINE')
    AND (`i3` = 'BRAND BANCARI|(NET) BANCOPOSTA')
    AND (`i4` = 'ANNO|2014')
) aaa )

LEFT JOIN (

    SELECT * FROM (

        (SELECT valore AS `vi1`
        FROM `i1`
        ) `ti1`,

        (SELECT valore AS `vi2`
        FROM `i2`
        ) `ti2`,

        (SELECT valore AS `vi3`
        FROM `i3`
        ) `ti3`,

        (SELECT valore AS `vi4`
        FROM `i4`
        ) `ti4`

    ) bbb
)  ON `ti1`.`vi1` = `dati`.`i1` AND `ti2`.`vi2` = `dati`.`i2`  AND `ti3`.`vi3` = `dati`.`i3`  AND `ti4`.`vi4` = `dati`.`i4`

这个看起来很酷但只是锁定MySQL FOREVER (!!!):

( select * from


( select * from
    (select valore as `vi1`,ordine as `oi1` from `i1`) `ti1`,
    (select valore as `vi2`,ordine as `oi2` from `i2`) `ti2`,
    (select valore as `vi3`,ordine as `oi3` from `i3`) `ti3`,
    (select valore as `vi4`,ordine as `oi4` from `i4`) `ti4`
) allkeys

left join

    (select * from `dati`
        where (`i1`= 'TARGET|TOTALE')
        AND (`i2`= 'BANCHE|ADV AWARENESS SPONTANEA OFFLINE')
        AND (`i3`= 'BRAND BANCARI|(NET) BANCOPOSTA')
        AND (`i4`= 'ANNO|2014') AND (TRUE)
    ) core

on ( `allkeys`.`vi1`=`core`.`i1` and `allkeys`.`vi2`=`core`.`i2`and `allkeys`.`vi3`=`core`.`i3` and `allkeys`.`vi4`=`core`.`i4` ) 
)

2 个答案:

答案 0 :(得分:1)

您可以通过连接实现所有这些,但由于您的数据很高,您必须index您的表,以便更快地进行查询响应。 您可以将索引应用于更频繁检索的列或在连接中反复使用的列。 同时尝试指定选择性列名而不是*,因为这样可以更快地处理列,而不是从所有列中提取数据。

答案 1 :(得分:0)

最后我选择了这样的查询:

SELECT `dati`.*
FROM `dati`
RIGHT JOIN `i2` ON `i2`.`valore` = `dati`.`i2`
RIGHT JOIN `i3` ON `i3`.`valore` = `dati`.`i3`
RIGHT JOIN `i4` ON `i4`.`valore` = `dati`.`i4`
WHERE (
`i1` = 'TARGET|INTERNAUTI'
OR `i1` = 'TARGET|INTERNAUTI SOCIAL'
)
AND (
`i2` = 'BANCHE|ADV AWARENESS SPONTANEA ONLINE'
OR `i2` = 'BANCHE|BRAND AWARENESS TOM'
)
AND (
`i3` = 'BRAND BANCARI|(NET) GRUPPO UCXREDIT'
OR `i3` = 'BRAND BANCARI|BANCA MECDIOUM'
)
AND (
`i4` = 'ANNO|2013'
OR `i4` = 'ANNO|2014'
)
AND (

TRUE
)
AND `i2`.`mostrare` =1
AND `i3`.`mostrare` =1
AND `i4`.`mostrare` =1

ORDER BY `i2`.`ordine` asc, `i3`.`ordine` asc, `i4`.`ordine` asc

需要表dati的所有i1-i4字段以及i1-i4表的valore,ordine和mostrare(= display)的索引,否则它将永远持续