MySQL 慢从视图中选择

use*_*970 5 mysql performance view query-performance

我很感激这个问题的方法,我在 mysql 中有一个彩票系统,这个系统每秒收到很多交易......很多!在允许下注之前,我需要检查每个数字的总金额,为此我有一个观点:

CREATE ALGORITHM=MERGE DEFINER=user@% SQL SECURITY DEFINER 
VIEW view_todays_bet AS select number, sum(bet_amout) as total_bet from salestable;
Run Code Online (Sandbox Code Playgroud)

有了这个视图,我就有了这个结果,例如:

Number total_bet

=====  ========

01 1500

05 2000

...

99 20
Run Code Online (Sandbox Code Playgroud)

所以当我有一个新的赌注时,我会从视图中进行选择,这就是问题出现的时候,例如,如果我想知道 05 号的余额,我会选择:

select total_bet from view_todays_bet where number = '05';
Run Code Online (Sandbox Code Playgroud)

如果我直接从主表进行选择,salestable我会被阻止,因为有很多来自其他投注的插入,但从视图中选择太慢。请给出一些关于这个问题的方法。

谢谢。

这是表的真实结构:标题/详细信息表和由两者连接而成的视图。

CREATE TABLE `sales_details` (
  `codpais` varchar(2) NOT NULL DEFAULT '',
  `numero` varchar(7) NOT NULL DEFAULT '',
  `verificador` varchar(10) NOT NULL DEFAULT '',
  `codterminal` varchar(8) NOT NULL DEFAULT '',
  `item` int(4) NOT NULL DEFAULT '1',
  `codloteria` varchar(3) NOT NULL DEFAULT '',
  `secuencia` varchar(2) NOT NULL DEFAULT '' COMMENT 'Aqui van los numeros jugados',
  `codjuego` varchar(3) NOT NULL DEFAULT '',
  `numeros` varchar(30) NOT NULL DEFAULT '' COMMENT 'Aqui van los numeros jugados',
  `monto` double NOT NULL DEFAULT '0',
  `numsorteos` int(11) NOT NULL DEFAULT '1',
  `horasorteo` varchar(5) NOT NULL DEFAULT '00:00',
  `codloteria2` varchar(3) NOT NULL DEFAULT '',
  `secuencia2` varchar(2) NOT NULL DEFAULT '',
  `nombrecorto2` varchar(30) NOT NULL DEFAULT '',
  `horasorteo2` varchar(5) NOT NULL DEFAULT '',
  `numerosganadores` varchar(10) NOT NULL DEFAULT '',
  `montopremio` double NOT NULL DEFAULT '0',
  `ganaprimero` double NOT NULL DEFAULT '0',
  `ganasegundo` double NOT NULL DEFAULT '0',
  `ganatercero` double NOT NULL DEFAULT '0',
  `ganacuarto` double NOT NULL DEFAULT '0',
  `porciento` double NOT NULL DEFAULT '0',
  PRIMARY KEY (`codpais`,`numero`,`verificador`,`codterminal`,`item`),
  KEY `codloteria` (`codloteria`),
  KEY `codjuego` (`codjuego`),
  KEY `codloteria2` (`codloteria2`)
) ENGINE=InnoDB;

CREATE TABLE `sales_header` (
  `codpais` varchar(2) NOT NULL DEFAULT '',
  `numero` varchar(7) NOT NULL DEFAULT '',
  `verificador` varchar(10) NOT NULL DEFAULT '',
  `codterminal` varchar(8) NOT NULL DEFAULT '',
  `stan` varchar(6) NOT NULL DEFAULT '',
  `tx` varchar(2) NOT NULL DEFAULT '',
  `cajero` varchar(15) NOT NULL DEFAULT '',
  `codempresa` varchar(2) NOT NULL DEFAULT '',
  `codbase` varchar(3) NOT NULL DEFAULT '',
  `codbanca` varchar(7) NOT NULL DEFAULT '',
  `codgrupo` varchar(2) NOT NULL DEFAULT '',
  `codprovincia` varchar(3) NOT NULL DEFAULT '',
  `codciudad` varchar(2) NOT NULL DEFAULT '',
  `codmunicipio` varchar(4) NOT NULL DEFAULT '',
  `codlocal` varchar(3) NOT NULL DEFAULT '',
  `total` double NOT NULL DEFAULT '0',
  `fechasorteo` date NOT NULL DEFAULT '0001-01-01',
  `fechasistema` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
  `fechapos` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
  `fechacancelacion` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
  `numerocancela` varchar(10) NOT NULL DEFAULT '',
  `terminalcancela` varchar(8) NOT NULL DEFAULT '',
  `turno` int(9) unsigned NOT NULL DEFAULT '0',
  `tasa` double NOT NULL DEFAULT '0',
  `esganador` varchar(1) NOT NULL DEFAULT 'N',
  `fuecobrado` varchar(1) NOT NULL DEFAULT 'N',
  `sorteocerrado` varchar(1) NOT NULL DEFAULT 'N',
  `fechacobrado` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
  `terminalcobrado` varchar(8) NOT NULL DEFAULT '',
  `usuariocobrado` varchar(15) NOT NULL DEFAULT '',
  `verificadorcobrado` varchar(20) NOT NULL DEFAULT '',
  `totalcobrado` double NOT NULL DEFAULT '0',
  `estatus` varchar(1) NOT NULL DEFAULT 'A' COMMENT 'A- Activo, R-Reversado, N-Anulada',
  `numrecarga` varchar(30) NOT NULL DEFAULT '',
  `autoincrecarga` varchar(4) NOT NULL DEFAULT '',
  `sincronizada` varchar(1) NOT NULL DEFAULT 'N',
  `reimpreso` varchar(1) NOT NULL DEFAULT 'N',
  `porciento` double NOT NULL DEFAULT '0',
  `bk` varchar(1) NOT NULL DEFAULT 'N',
  `codcliente` varchar(5) NOT NULL DEFAULT '',
  `calcporciento` varchar(1) NOT NULL DEFAULT 'T',
  PRIMARY KEY (`codpais`,`numero`,`verificador`,`codterminal`),
  KEY `stan` (`stan`),
  KEY `tx` (`tx`),
  KEY `fechasorteo` (`fechasorteo`),
  KEY `fechasistema` (`fechasistema`),
  KEY `estatus` (`estatus`),
  KEY `codconsorcio` (`codbase`),
  KEY `codempresa` (`codempresa`),
  KEY `codbanca` (`codbanca`),
  KEY `codgrupo` (`codgrupo`),
  KEY `bk` (`bk`),
  KEY `codcliente` (`codcliente`),
  KEY `esganador` (`esganador`),
  KEY `numrecarga` (`numrecarga`)
) ENGINE=InnoDB;

CREATE ALGORITHM=UNDEFINED DEFINER=`user`@`%` SQL SECURITY DEFINER VIEW `view_todays_bet` AS select `vd`.`codpais` AS `codpais`,`vd`.`codloteria` AS `codloteria`,`vd`.`codjuego` AS `codjuego`,sum(`vd`.`monto`) AS `monto`,`fnNumeroCRC`(`vd`.`numeros`) AS `crc` from (`sales_details` `vd` join `sales_header` `vh`) where ((`vd`.`codpais` = `vh`.`codpais`) and (`vd`.`numero` = `vh`.`numero`) and (`vd`.`verificador` = `vh`.`verificador`) and (`vd`.`codterminal` = `vh`.`codterminal`) and (`vh`.`fechasorteo` = date_format(sysdate(),'%Y-%m-%d')) and (`vh`.`estatus` = 'A')) 
group by 1,2,3,5 
order by 1,2,3,5
Run Code Online (Sandbox Code Playgroud)

Der*_*ney 6

这里发生了一些事情:

  • 您的CREATE VIEW语句包含一个SUM()函数。即使您ALGORITHM被指定为MERGE,它也确实会TEMPTABLE此处的文档中所讨论的那样:

    如果无法使用 MERGE 算法,则必须改用临时表。如果视图包含以下任何构造,则不能使用 MERGE:聚合函数(SUM()、MIN()、MAX()、COUNT() 等)

  • 所以我们使用临时表。由于 TEMPTABLE 算法的这种好处,我怀疑您没有看到“阻塞”:

    显式选择 TEMPTABLE 的一个原因是可以在创建临时表之后且在使用它完成语句处理之前释放基础表上的锁。这可能会导致比 MERGE 算法更快的锁定释放,以便使用该视图的其他客户端不会被阻塞那么长时间。

  • 但是,该TEMPTABLE算法的问题在于它们没有/使用索引[src]

    视图处理未优化:

    无法在视图上创建索引。

    索引可用于使用合并算法处理的视图。但是,使用临时表算法处理的视图无法利用其基础表上的索引(尽管可以在生成临时表期间使用索引)。

所以现在我们需要知道你的表的底层结构为什么直接查询阻塞:

  • 如果不是InnoDB,考虑改用行级锁,而不是MyISAM的表锁
  • 如果 ( number, bet_amount)上没有索引,请考虑创建一个。

如果上述几点已经完成,并且您仍然出于某种原因阻止了直接针对salestable表的查询,那么您可以通过创建触发器来修改具有每个数字和运行总数的临时表,从而建立穷人的物化视图.