web-dev-qa-db-ja.com

MySQLのビューからの遅い選択

私はこの問題のアプローチに感謝します、私はmysqlに宝くじシステムを持っています、このシステムは毎秒多くのトランザクションを受け取ります。ベットを許可する前に、各番号の合計金額を確認する必要があります。この目的のために、次のように考えています。

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

このビューでは、たとえば次のような結果になります。

Number total_bet

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

01 1500

05 2000

...

99 20

新しいベットがあるときは、ビューから選択を行い、それが問題が発生した瞬間です。たとえば、05番の残高を知りたい場合は、この選択を行います。

select total_bet from view_todays_bet where number = '05';

メインテーブルから直接選択を行うと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
5
user2286970

ここでいくつかのことが起こっています:

  • _CREATE VIEW_ステートメントにSUM()関数が含まれています。あなたのALGORITHMMERGEとして指定されていますが、ドキュメントで説明されているように、実際にはTEMPTABLEになります here

    MERGEアルゴリズムを使用できない場合は、代わりに一時テーブルを使用する必要があります。ビューに次の構成要素のいずれかが含まれている場合、MERGEは使用できません。集計関数(SUM()、MIN()、MAX()、COUNT()など)

  • したがって、一時テーブルを使用しています。 TEMPTABLEアルゴリズムのこの利点により、「ブロック」が表示されないのではないかと思います。

    TEMPTABLEを明示的に選択する理由は、一時テーブルが作成された後、ステートメントの処理を完了するために使用される前に、基礎となるテーブルのロックを解放できるためです。これにより、MERGEアルゴリズムよりも迅速にロックが解放されるため、ビューを使用する他のクライアントがブロックされないようにします。

  • ただし、TEMPTABLEアルゴリズムの問​​題は、インデックスがない/使用しないことです [src]

    ビュー処理は最適化されていません:

    ビューにインデックスを作成することはできません。

    インデックスは、マージアルゴリズムを使用して処理されたビューに使用できます。ただし、temptableアルゴリズムで処理されるビューは、基になるテーブルのインデックスを利用できません(ただし、一時テーブルの生成中にインデックスを使用できます)。

したがって、直接クエリがブロックされる理由について、テーブルの基本的な構造を知る必要があります。

  • InnoDBでない場合は、MyISAMのテーブルロックの代わりに行レベルのロックを使用するように切り替えることを検討してください
  • number、_bet_amount_)にインデックスがない場合は、作成することを検討してください。

上記のポイントが既に実行されていて、何らかの理由でsalestableテーブルに対するクエリを直接ブロックしている場合、一時テーブルを変更するトリガーを作成して、貧しい人々のマテリアライズドビューを設定できます。各番号と現在の合計。

6
Derek Downey

遅いビュー

代替ソリューションで解決

機能的な代替案は、パラメーターを渡して、ビュークエリをプロシージャにカプセル化することです。これは、複数のテーブル間で複数の結合クエリを使用してVIEWSが遅くなるという問題を改善する簡単なソリューションです。

DELIMITER ;;
CREATE PROCEDURE `SP_QUERY_VIEW_WITH_PARAMETERS`(IN p_having VARCHAR(300))
    COMMENT 'Executes the statement'
BEGIN
  SET @v_having = p_having;
  SET @v_sql=CONCAT('SELECT 
                    id    AS id_emp  ,
                    user  AS emp_name,
                    .
                    .
                    .
                    FROM table1
                    UNION ALL
                    SELECT 
                    idtifier_us    AS id_emp  ,
                    description    AS emp_name,
                    .
                    .
                    .
                    FROM table2');
SET @v_sql2 = CONCAT(@v_sql,@v_having);
  PREPARE stmt FROM @v_sql2;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
END ;;
DELIMITER ;

CALL `SP_QUERY_VIEW_WITH_PARAMETERS`('having id_emp=63 and emp_name like ''VANDERLEI%'' and created_at between ''2019-05-01'' and ''2019-05-17''  ');

この代替案は、クエリの実行時にインデックスによる最適化を保持します

注:「どこ」でも使用できますが、より単純なクエリを使用します