6

私は mysql のビューを持っています:

CREATE VIEW
    loggingquarantine_quarantine ( id, mail_id, partition_tag, content, rs, subject, sender, TIME,
    spam_level, size, sid, email ) AS
SELECT
    concat(CAST(`mr`.`mail_id` AS CHAR(255) charset utf8),CAST(`mr`.`partition_tag` AS CHAR(255)
    charset utf8))      AS `id`,
    `mr`.`mail_id`       AS `mail_id`,
    `mr`.`partition_tag` AS `partition_tag`,
    `mr`.`content`      AS `content`,
    `mr`.`rs`           AS `rs`,
    `m`.`subject`       AS `subject`,
    `m`.`from_addr`     AS `sender`,
    `m`.`time_num`      AS `TIME`,
    `m`.`spam_level`    AS `spam_level`,
    `m`.`size`          AS `size`,
    `m`.`sid`           AS `sid`,
    `maddr`.`email`          AS `email`
FROM
    (((`msgrcpt` `mr` JOIN `msgs` `m`
ON
    (
                `m`.`partition_tag` = `mr`.`partition_tag`
        AND
                `m`.`mail_id` = `mr`.`mail_id`
    )
)
JOIN `maddr` maddr
ON
    (
        `mr`.`rid` = `maddr`.`id`
    )
))

このビューをカウントしようとすると、250 万のレコードに約 13 分かかります。それは信じられないほど遅いです。すべてのフィールドにはインデックスがあります。各テーブルを数えると、20 秒もかかりません。mysql Explain が示す内容は次のとおりです。

mysql> explain SELECT COUNT(*) FROM `loggingquarantine_quarantine`;
+----+-------------+-------+--------+-----------------------------------------------------------------------+-------------------------+---------+-----------------------------------------------------------+---------+-------------+
| id | select_type | table | type   | possible_keys                                                         | key                     | key_len | ref                                                       | rows    | Extra       |
+----+-------------+-------+--------+-----------------------------------------------------------------------+-------------------------+---------+-----------------------------------------------------------+---------+-------------+
|  1 | SIMPLE      | maddr | index  | PRIMARY                                                               | maddr_partition_tag_idx | 5       | NULL                                                      | 1016497 | Using index |
|  1 | SIMPLE      | mr    | ref    | PRIMARY,msgrcpt_idx_rid,msgrcpt_mail_id_idx,msgrcpt_partition_tag_idx | msgrcpt_idx_rid         | 8       | mroute_logquar.maddr.id                                   |       2 | Using index |
|  1 | SIMPLE      | m     | eq_ref | PRIMARY,msgs_mail_id_idx,msgs_partition_tag_idx                       | PRIMARY                 | 22      | mroute_logquar.mr.partition_tag,mroute_logquar.mr.mail_id |       1 | Using index |
+----+-------------+-------+--------+-----------------------------------------------------------------------+-------------------------+---------+-----------------------------------------------------------+---------+-------------+

カウントを行うのに 13 分もかからないようにクエリ/ビューを最適化するにはどうすればよいですか? 現在のクエリの何が問題になっていますか?

アップデート。ビューなしで選択して選択カウントを直接実行すると、同じ14分のクエリが取得されます。

mysql> select count(1) FROM     (((`msgrcpt` `mr` JOIN `msgs` `m` ON     (                  `m`.`partition_tag` = `mr`.`partition_tag`         AND                 `m`.`mail_id` = `mr`.`mail_id`      ) ) JOIN `maddr` maddr ON     (         `mr`.`rid` = `maddr`.`id`     ) ));

+----------+
| count(1) |
+----------+
|  2582227 |
+----------+
1 row in set (14 min 28.96 sec)

そして、3 つの別々のクエリで実行したときの count の結果は次のとおりです。

mysql> select count(1) from msgrcpt;
+----------+
| count(1) |
+----------+
|  2587307 |
+----------+
1 row in set (46.02 sec)

mysql> select count(1) from msgs;
+----------+
| count(1) |
+----------+
|  2421710 |
+----------+
1 row in set (7.77 sec)

mysql> select count(1) from maddr;
+----------+
| count(1) |
+----------+
|   994880 |
+----------+
1 row in set (0.23 sec)

更新 2。

すべてのテーブルは InnoDB です。

mysql> SHOW status like 'key_%';                                                                                                                                                                               +------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| Key_blocks_not_flushed | 0     |
| Key_blocks_unused      | 26792 |
| Key_blocks_used        | 0     |
| Key_read_requests      | 0     |
| Key_reads              | 0     |
| Key_write_requests     | 0     |
| Key_writes             | 0     |
+------------------------+-------+

msgs および msgrcpt テーブルには、複合主キー (msgs の mail_id、partation_tag、および msgrpt の ( partition_tag, mail_id, rseqnum)) があります。単一テーブルの UPDATE Explain:

mysql> explain select count(1) from msgs;
+----+-------------+-------+-------+---------------+-------------------+---------+------+---------+-------------+
| id | select_type | table | type  | possible_keys | key               | key_len | ref  | rows    | Extra       |
+----+-------------+-------+-------+---------------+-------------------+---------+------+---------+-------------+
|  1 | SIMPLE      | msgs  | index | NULL          | msgs_idx_time_num | 4       | NULL | 2357360 | Using index |
+----+-------------+-------+-------+---------------+-------------------+---------+------+---------+-------------+
1 row in set (0.00 sec)

mysql> explain select count(1) from msgrcpt;
+----+-------------+---------+-------+---------------+----------------+---------+------+---------+-------------+
| id | select_type | table   | type  | possible_keys | key            | key_len | ref  | rows    | Extra       |
+----+-------------+---------+-------+---------------+----------------+---------+------+---------+-------------+
|  1 | SIMPLE      | msgrcpt | index | NULL          | msgrcpt_rs_idx | 3       | NULL | 2620758 | Using index |
+----+-------------+---------+-------+---------------+----------------+---------+------+---------+-------------+
1 row in set (0.00 sec)

mysql> explain select count(1) from maddr;
+----+-------------+-------+-------+---------------+-------------------------+---------+------+--------+-------------+
| id | select_type | table | type  | possible_keys | key                     | key_len | ref  | rows   | Extra       |
+----+-------------+-------+-------+---------------+-------------------------+---------+------+--------+-------------+
|  1 | SIMPLE      | maddr | index | NULL          | maddr_partition_tag_idx | 5       | NULL | 967058 | Using index |
+----+-------------+-------+-------+---------------+-------------------------+---------+------+--------+-------------+
1 row in set (0.00 sec)

アップデート。すべてのテーブルのテーブルを作成します。

mysql> show create table msgrcpt;
| Table   | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
| msgrcpt | CREATE TABLE `msgrcpt` (
  `partition_tag` int(11) NOT NULL DEFAULT '0',
  `mail_id` varbinary(16) NOT NULL,
  `rseqnum` int(11) NOT NULL DEFAULT '0',
  `rid` bigint(20) unsigned NOT NULL,
  `is_local` char(1) NOT NULL DEFAULT '',
  `content` char(1) NOT NULL DEFAULT '',
  `ds` char(1) NOT NULL,
  `rs` char(1) NOT NULL,
  `bl` char(1) DEFAULT '',
  `wl` char(1) DEFAULT '',
  `bspam_level` float DEFAULT NULL,
  `smtp_resp` varchar(255) DEFAULT '',
  PRIMARY KEY (`partition_tag`,`mail_id`,`rseqnum`),
  KEY `msgrcpt_idx_rid` (`rid`),
  KEY `msgrcpt_mail_id_idx` (`mail_id`),
  KEY `msgrcpt_rs_idx` (`rs`),
  KEY `msgrcpt_ds_idx` (`ds`),
  KEY `msgrcpt_partition_tag_idx` (`partition_tag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

| msgs  | CREATE TABLE `msgs` (
  `partition_tag` int(11) NOT NULL DEFAULT '0',
  `mail_id` varbinary(16) NOT NULL,
  `secret_id` varbinary(16) DEFAULT '',
  `am_id` varchar(20) NOT NULL,
  `time_num` int(10) unsigned NOT NULL,
  `time_iso` char(16) NOT NULL,
  `sid` bigint(20) unsigned NOT NULL,
  `policy` varchar(255) DEFAULT '',
  `client_addr` varchar(255) DEFAULT '',
  `size` int(10) unsigned NOT NULL,
  `originating` char(1) NOT NULL DEFAULT '',
  `content` char(1) DEFAULT NULL,
  `quar_type` char(1) DEFAULT NULL,
  `quar_loc` varbinary(255) DEFAULT '',
  `dsn_sent` char(1) DEFAULT NULL,
  `spam_level` float DEFAULT NULL,
  `message_id` varchar(255) DEFAULT '',
  `from_addr` varchar(255) DEFAULT '',
  `subject` varchar(255) DEFAULT '',
  `host` varchar(255) NOT NULL,
  PRIMARY KEY (`partition_tag`,`mail_id`),
  KEY `msgs_idx_sid` (`sid`),
  KEY `msgs_idx_mess_id` (`message_id`),
  KEY `msgs_idx_time_num` (`time_num`),
  KEY `msgs_mail_id_idx` (`mail_id`),
  KEY `msgs_partition_tag_idx` (`partition_tag`),
  KEY `msgs_content_idx` (`content`),
  FULLTEXT KEY `ft_from_addr` (`from_addr`),
  FULLTEXT KEY `ft_subject` (`subject`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

| maddr | CREATE TABLE `maddr` (
  `partition_tag` int(11) DEFAULT '0',
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `email` varbinary(255) NOT NULL,
  `domain` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `part_email` (`partition_tag`,`email`),
  KEY `maddr_email_idx` (`email`),
  KEY `maddr_partition_tag_idx` (`partition_tag`)
) ENGINE=InnoDB AUTO_INCREMENT=3373444 DEFAULT CHARSET=utf8 |

プロファイルを使用したこのクエリ:

mysql> SET PROFILING=1; SELECT
Query OK, 0 rows affected (0.00 sec)

    -> count(1)
    -> FROM
    ->     (((`msgrcpt` `mr` JOIN `msgs` `m`
    -> ON
    ->     (
    ->                 `m`.`partition_tag` = `mr`.`partition_tag`
    ->         AND
    ->                 `m`.`mail_id` = `mr`.`mail_id`
    ->     )
    -> )
    -> JOIN `maddr` maddr
    -> ON
    ->     (
    ->         `mr`.`rid` = `maddr`.`id`
    ->     )
    -> )); SHOW PROFILE ALL;

+----------+
| count(1) |
+----------+
|  4279394 |
+----------+
1 row in set (23 min 56.61 sec)

+----------------------+------------+-----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+------------------+-------------+
| Status               | Duration   | CPU_user  | CPU_system | Context_voluntary | Context_involuntary | Block_ops_in | Block_ops_out | Messages_sent | Messages_received | Page_faults_major | Page_faults_minor | Swaps | Source_function       | Source_file      | Source_line |
+----------------------+------------+-----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+------------------+-------------+
| starting             |   0.000161 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | NULL                  | NULL             |        NULL |
| checking permissions |   0.000030 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 1 |     0 | check_access          | sql_parse.cc     |        5043 |
| checking permissions |   0.000019 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | check_access          | sql_parse.cc     |        5043 |
| checking permissions |   0.000020 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | check_access          | sql_parse.cc     |        5043 |
| Opening tables       |   0.000039 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | open_tables           | sql_base.cc      |        5014 |
| System lock          |   0.000026 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_lock_tables     | lock.cc          |         304 |
| init                 |   0.000040 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_select          | sql_select.cc    |        1041 |
| optimizing           |   0.000030 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | optimize              | sql_optimizer.cc |         138 |
| statistics           |   0.000063 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | optimize              | sql_optimizer.cc |         358 |
| preparing            |   0.000032 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | optimize              | sql_optimizer.cc |         470 |
| executing            |   0.000021 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | exec                  | sql_executor.cc  |         137 |
| Sending data         | 999.999999 | 97.014251 |  10.376423 |            681167 |               25822 |      5157072 |       1951032 |             0 |                 0 |                 4 |               277 |     0 | execute               | sql_executor.cc  |         758 |
| end                  |   0.000106 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_select          | sql_select.cc    |        1071 |
| query end            |   0.000017 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_execute_command | sql_parse.cc     |        4761 |
| closing tables       |   0.000021 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_execute_command | sql_parse.cc     |        4809 |
| freeing items        |   0.000030 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_parse           | sql_parse.cc     |        5997 |
| logging slow query   |   0.000059 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             8 |             0 |                 0 |                 0 |                 0 |     0 | log_slow_statement    | sql_parse.cc     |        1720 |
| cleaning up          |   0.000019 |  0.000000 |   0.000000 |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | dispatch_command      | sql_parse.cc     |        1654 |
+----------------------+------------+-----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+------------------+-------------+
18 rows in set (0.02 sec)

テーブルのインデックス:

mysql> show index from msgs;
+-------+------------+------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name               | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| msgs  |          0 | PRIMARY                |            1 | partition_tag | A         |          16 |     NULL | NULL   |      | BTREE      |         |               |
| msgs  |          0 | PRIMARY                |            2 | mail_id       | A         |     4174440 |     NULL | NULL   |      | BTREE      |         |               |
| msgs  |          1 | msgs_idx_sid           |            1 | sid           | A         |     2087220 |     NULL | NULL   |      | BTREE      |         |               |
| msgs  |          1 | msgs_idx_mess_id       |            1 | message_id    | A         |     4174440 |     NULL | NULL   | YES  | BTREE      |         |               |
| msgs  |          1 | msgs_idx_time_num      |            1 | time_num      | A         |     1391480 |     NULL | NULL   |      | BTREE      |         |               |
| msgs  |          1 | msgs_mail_id_idx       |            1 | mail_id       | A         |     4174440 |     NULL | NULL   |      | BTREE      |         |               |
| msgs  |          1 | msgs_partition_tag_idx |            1 | partition_tag | A         |          16 |     NULL | NULL   |      | BTREE      |         |               |
| msgs  |          1 | msgs_content_idx       |            1 | content       | A         |          16 |     NULL | NULL   | YES  | BTREE      |         |               |
| msgs  |          1 | ft_from_addr           |            1 | from_addr     | NULL      |     4174440 |     NULL | NULL   | YES  | FULLTEXT   |         |               |
| msgs  |          1 | ft_subject             |            1 | subject       | NULL      |     4174440 |     NULL | NULL   | YES  | FULLTEXT   |         |               |
+-------+------------+------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
10 rows in set (0.97 sec)

MSGRCPT

mysql> show index from msgrcpt;
+---------+------------+---------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table   | Non_unique | Key_name                  | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+---------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| msgrcpt |          0 | PRIMARY                   |            1 | partition_tag | A         |          29 |     NULL | NULL   |      | BTREE      |         |               |
| msgrcpt |          0 | PRIMARY                   |            2 | mail_id       | A         |     5218535 |     NULL | NULL   |      | BTREE      |         |               |
| msgrcpt |          0 | PRIMARY                   |            3 | rseqnum       | A         |     5218535 |     NULL | NULL   |      | BTREE      |         |               |
| msgrcpt |          1 | msgrcpt_idx_rid           |            1 | rid           | A         |      347902 |     NULL | NULL   |      | BTREE      |         |               |
| msgrcpt |          1 | msgrcpt_mail_id_idx       |            1 | mail_id       | A         |     5218535 |     NULL | NULL   |      | BTREE      |         |               |
| msgrcpt |          1 | msgrcpt_rs_idx            |            1 | rs            | A         |          29 |     NULL | NULL   |      | BTREE      |         |               |
| msgrcpt |          1 | msgrcpt_ds_idx            |            1 | ds            | A         |          29 |     NULL | NULL   |      | BTREE      |         |               |
| msgrcpt |          1 | msgrcpt_partition_tag_idx |            1 | partition_tag | A         |          29 |     NULL | NULL   |      | BTREE      |         |               |
+---------+------------+---------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
8 rows in set (0.70 sec)

MADDR:

mysql> show index from maddr;
+-------+------------+-------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name                | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| maddr |          0 | PRIMARY                 |            1 | id            | A         |     1653970 |     NULL | NULL   |      | BTREE      |         |               |
| maddr |          0 | part_email              |            1 | partition_tag | A         |          19 |     NULL | NULL   | YES  | BTREE      |         |               |
| maddr |          0 | part_email              |            2 | email         | A         |     1653970 |     NULL | NULL   |      | BTREE      |         |               |
| maddr |          1 | maddr_email_idx         |            1 | email         | A         |     1653970 |     NULL | NULL   |      | BTREE      |         |               |
| maddr |          1 | maddr_partition_tag_idx |            1 | partition_tag | A         |          19 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+-------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
5 rows in set (0.41 sec)

Inno db バッファ サイズ

mysql> SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
+-------------------------+------------+
| Variable_name           | Value      |
+-------------------------+------------+
| innodb_buffer_pool_size | 2147483648 |
+-------------------------+------------+
1 row in set (0.02 sec)
4

9 に答える 9

1

単純な JOIN の代わりにいくつかの STRAIGHT_JOIN を使用して、JOIN で使用されるテーブルの順序を変えてみましたか? クエリ オプティマイザーが特定のクエリの理想的な順序を選択しないことがあります。言い換えれば、これでどのようなパフォーマンスが見られますか?

SELECT
  concat(CAST(`mr`.`mail_id` AS CHAR(255) charset utf8),CAST(`mr`.`partition_tag` AS CHAR(255) charset utf8)) AS `id`,
  `mr`.`mail_id`       AS `mail_id`,
  `mr`.`partition_tag` AS `partition_tag`,
  `mr`.`content`      AS `content`,
  `mr`.`rs`           AS `rs`,
  `m`.`subject`       AS `subject`,
  `m`.`from_addr`     AS `sender`,
  `m`.`time_num`      AS `TIME`,
  `m`.`spam_level`    AS `spam_level`,
  `m`.`size`          AS `size`,
  `m`.`sid`           AS `sid`,
  `maddr`.`email`          AS `email`
FROM
  `msgrcpt` `mr`
    STRAIGHT_JOIN `msgs` `m`
      ON
        `m`.`partition_tag` = `mr`.`partition_tag` AND
        `m`.`mail_id` = `mr`.`mail_id`
    STRAIGHT_JOIN `maddr` maddr
      ON
        `mr`.`rid` = `maddr`.`id`

または、いくつかの負荷の高い変換と msgrcpt テーブルでのキャストを使用しているため、このようにクエリの最後に強制的に JOIN するとどうなりますか?

SELECT
  concat(CAST(`mr`.`mail_id` AS CHAR(255) charset utf8),CAST(`mr`.`partition_tag` AS CHAR(255) charset utf8)) AS `id`,
  `mr`.`mail_id`       AS `mail_id`,
  `mr`.`partition_tag` AS `partition_tag`,
  `mr`.`content`      AS `content`,
  `mr`.`rs`           AS `rs`,
  `m`.`subject`       AS `subject`,
  `m`.`from_addr`     AS `sender`,
  `m`.`time_num`      AS `TIME`,
  `m`.`spam_level`    AS `spam_level`,
  `m`.`size`          AS `size`,
  `m`.`sid`           AS `sid`,
  `maddr`.`email`          AS `email`
FROM
  `maddr` `maddr`
    STRAIGHT_JOIN `msgrcpt` `mr`
      ON
        `maddr`.`id` = `mr.`rid`
    STRAIGHT_JOIN `msgs` `m`
      ON
        `m`.`partition_tag` = `mr`.`partition_tag` AND
        `m`.`mail_id` = `mr`.`mail_id`

必要に応じて、順序をさらにいじることができます。クエリを圧縮する「魔法の順序」が存在する可能性があります。たとえば、別のバリエーションは次のようになります。

FROM
  `msgs` `m`
    STRAIGHT_JOIN `msgrcpt` `mr`
      ON
        `m`.`partition_tag` = `mr`.`partition_tag` AND
        `m`.`mail_id` = `mr`.`mail_id`
    STRAIGHT_JOIN `maddr`
      ON
        `maddr`.`id` = `mr`.`rid`

...等々。

また、SELECT 列では、そのキャストのすべてがパフォーマンスを少し犠牲にすることになります。これは、選択している行の数が多くなる可能性があるためです。既に計算されている msgrcpt テーブルに列を追加して、クエリでそれを行う必要がないようにすることを検討しましたか? コード内の余分な列を考慮してだまされたくない場合は、データベースにトリガーを追加して、計算された値で効率的かつ自動的に更新することができます。通常、この種の最適化を使用するのは少しやり過ぎですが、何百万もの行に対して SELECT クエリを実行する場合は、うまくいくかもしれません。

編集: msgrcptテーブルを変更するために私が提案することは次のとおりです。新しい列の値を計算するトリガーを実行しているため、行の挿入が非常に遅くなりますが、実行しようとしているクエリの速度がかなり向上すると思います。標準の免責事項が適用されます。最初にテスト コピーで十分にテストすることなく、本番データベースでこれを実行しないでください。

-- The UPDATE command will probably take some time to run since it's updating
-- millions of rows. Be patient!
ALTER TABLE `msgrcpt` ADD COLUMN `friendly_id` TEXT NULL AFTER `rs`;
UPDATE `msgrcpt` SET
  `friendly_id` = CONCAT(CAST(`mail_id` AS CHAR(255) CHARSET utf8),
    CAST(`partition_tag` AS CHAR(255) CHARSET utf8));
DELIMITER $$
CREATE TRIGGER `trig_calc_id` BEFORE INSERT ON `msgrcpt`
  FOR EACH ROW BEGIN
    SET NEW.`friendly_id` =
      CONCAT(CAST(NEW.`mail_id` AS CHAR(255) CHARSET utf8),
        CAST(NEW.`partition_tag` AS CHAR(255) CHARSET utf8));
  END $$
CREATE TRIGGER `trig_update_id` BEFORE UPDATE ON `msgrcpt`
  FOR EACH ROW BEGIN
    SET NEW.`friendly_id` =
      CONCAT(CAST(NEW.`mail_id` AS CHAR(255) CHARSET utf8),
        CAST(NEW.`partition_tag` AS CHAR(255) CHARSET utf8));
  END $$
DELIMITER ;

CONCATed CASTed の混乱した混乱を選択する代わりに、mr.friendly_id (または列に名前を付けるために選択したもの) を選択するだけです。あなたのパフォーマンスはずっと良くなるはずです。

これが役立つことを願って、それがどうなるか教えてください!

于 2012-07-01T18:28:58.500 に答える
0

MySQLオプティマイザはかなりバグがあるため、COUNT(*)insted COUNT(1)を使用してみて くださいhttp://www.mysqlperformanceblog.com/2007/04/10/count-vs-countcol/

于 2012-07-05T13:45:44.957 に答える
0

Join には大きな mysql 負荷が必要です。私の経験では、一時テーブルを作成してそこからデータを選択し、db クエリの速度を上げます。

これは私のコードです。コード 2 は 100 倍の速さを示しています。コード 2 スタイルのようにクエリ コードを変更できます。大規模で複雑な db クエリの場合は、一時テーブルを使用して db クエリ速度を向上させます。

  1. 一時テーブルを作成すると、クエリが単純になり、mysql db の負荷が軽減されます。
  2. 一時テーブルからデータを選択すると、データベースの負荷も少なくて済みます。

コード 1

    $sql = " select distinct wr_parent from $write_table where $sql_search ";
    $result = sql_query($sql);
    $total_count = mysql_num_rows($result);

コード 2

    $sql = " select wr_parent from $write_table where $sql_search ";
    $sql_tmp = " create TEMPORARY table list_tmp_count as $sql ";
    $sql_ord = " select distinct wr_parent from list_tmp_count ";

    @mysql_query($sql_tmp) or die("<p>$sql_tmp<p>" . mysql_errno() . " : " .  mysql_error() . "<p>error file : $_SERVER[PHP_SELF]");
    $result = @mysql_query($sql_ord) or die("<p>$sql_ord<p>" . mysql_errno() . " : " .  mysql_error() . "<p>error file : $_SERVER[PHP_SELF]");
    $total_count = mysql_num_rows($result);

mysql一時テーブル

また、一時テーブルの場所をtempfs(メモリ領域)に置くと、速度も2倍になります。

于 2012-07-08T07:50:07.523 に答える
0

データベースがテーブル結合を実行する方法はいくつかあります。MySQL は、 outputのセクションで説明されているように、ネスト ループ結合のみを使用しています。ネストされたループの仕組みは、このクエリに時間がかかる理由を理解するための鍵です。EXPLAIN

出力によるとEXPLAIN、MySQL は最初にテーブルをスキャンしてmaddrいるため、実行のループがあります1 016 497。各実行データベース内では、小さなテーブルに対してインデックス スキャンが 2 回実行されます。たとえ以下のコストであっても:

  • 新しいインデックス スキャンを開始します。
  • インデックス内のエントリを検索します。
  • スキャンのファイナライズ

非常に小さいため (データは多くの実行でキャッシュされる可能性が高いため)、とにかく数ミリ秒かかります。2次に、を掛けます。msgrcptmsgsは両方とも内部でスキャンされます。そして、外側のループの実行回数を掛けると、かなりの時間が得られます。

ビュー定義には、返されたデータに対するフィルターがないため、すべてのテーブルをスキャンして結合する必要があります。ネストされたループがどのように機能するかを考えると、外側のクエリに含まれるサイクルの量が最も少ないバリアントが最もパフォーマンスの高いものであることは明らかです。すべてのテーブルのサイズを考慮して、インデックス スキャン (3 つのテーブルすべてがEXPLAIN出力に従ってインデックスでスキャンされます) を調べます。

  • msgrcpt: ログ2 (2587307) + 1 = 22 ページ、
  • msgs: ログ2 (2421710) + 1 = 22 ページおよび
  • maddr: ログ2 (994880) + 1 = スキャンごとに 21 ページ

最悪のシナリオで。これは、インデックス スキャンを使用した場合でも、テーブル スキャン時間が同等であり、非常に重要であることを示しています。それでもmaddrは小さく、これが MySQL が最初にスキャンすることを選択した理由です。

私が見たところ、データベースによって選択された計画は、与えられた状況で最良のものです。また、MySQL がネストされたループ結合のみをサポートしているという事実は、外側のループがすでに最小のものであるため、最適化の可能性を提供しません。ここでは、パフォーマンスを向上させるためにハッシュ結合が使用された可能性があります。


では、この状況で物事を機能させるにはどうすればよいでしょうか。

フィルターを使用してデータをクエリする場合はビューのみを使用することをお勧めします。これにより、MySQL がクエリを最適化し、データを高速に返す機会が増えます。

行数を取得するには、見積もりを行い(これが許容できる場合)、count(*)個々のテーブルごとに計算し、最大のものを取得します。

もう 1 つの方法は、ビューの行数が常にマスター テーブルの行数と一致するように、スキーマを再設計してテーブルの 1 つをマスター テーブルにすることです。指定されたデザインでこれを行う方法がわかりません。申し訳ありません。

どのオプションも受け入れられない場合、残念ながら、このクエリを最適化する方法は他にありません。

于 2012-07-01T21:54:20.630 に答える
0

すみません: あなたの maddr テーブルには partition_tag id がありますが、そのパーティション タグは VIEW を構成する最後の JOIN で使用されていません。これはあるべき姿ですか?

とにかく、id と email の両方を含む maddr のインデックスがクエリに役立つようです。これにより、少ない I/O で直接インデックスから電子メールを抽出できるようになるはずです (さまざまなインデックスのパフォーマンスを評価することはおそらく有益でしょう。たとえば、電子メール フィールドのインデックスのみを使用することはめったにないように思えますが、あなたが知っていて、私が知らないワークフローに依存するため、間違っている可能性があります。

于 2012-07-06T18:58:49.033 に答える
0

パフォーマンスは、ビュー クエリ自体、およびコード内でのビューの使用によって影響を受ける場合があります。詳細については、パフォーマンスのトラブルメーカーとしての MySQL VIEWの記事を参照してください。

回避策:

  • ビューを使用せずに、単純なクエリを実行します。
  • このビューを別の SELECT ステートメントでデータセットとして使用したくない場合は、ビューの代わりにストアド プロシージャを作成してみてください。
于 2012-07-04T06:42:15.057 に答える
0

2 つの要素について King Skippus に同意します... オプティマイザの実行計画を覆すのに役立つ STRAIGHT_JOIN... と、事前集計を保持するためのトリガー。ただし、制限するために WHERE 句を適用したい場合は、撃たれます。

さらに、気になるのが COUNT だけの場合は、すべての列を破棄する vyegorov コメントが最適です。他のすべての列を使用することで、実際のすべてのデータ ページからデータが強制的に取得されます。

クエリを次のようにレンダリングします

SELECT STRAIGHT_JOIN COUNT(*)
   FROM
      msgrcpt mr
         JOIN msgs m
            ON mr.mail_id = m.mail_id
           AND mr.partition_tag = m.partition_tag
         JOIN maddr
            ON mr.rid = maddr.id

そして、あなたがインデックスについて言及したことは知っていますが、(mail_id、partition_tag) を介して MsgRcpt テーブル インデックスを作成します。同じ (mail_id、partition_tag) MAddr インデックスを介して (id)

では、インデックスの一方通行と他方通行はなぜ異なるのでしょうか。最初のインデックス フィールドの最小の集計に基づいて実行しようとします。ボリューム ベース (メール ID、パーティション タグ) が正確にはわかりませんが、顧客注文システムのサンプルを取り上げます。1 日に 10,000 人が何かを注文する可能性がありますが、特定の人については、特定の日に 1 つまたは 2 つの注文があります。最初にその人を見つけ、その個々の日付と 1 日で 1 人の人を見つける方が簡単です。これは、最初に大きなリストを通過しようとするクエリのパフォーマンスに影響を与える可能性があります。次に、小さいリストと小さい/小さいリストを比較します。

COUNT(*) を実行するだけで、それだけのカウントが得られます。生のテーブルからの追加の列は必要なく、結果のレコードを修飾するために必要なのはインデックス付きコンポーネントのみであるため、すべてのページが読み込まれます。

すべてのデータが必要な場合は、上記と同じインデックスの考慮事項を行いますが、クエリは...

CREATE VIEW
    loggingquarantine_quarantine ( id, mail_id, partition_tag, content, rs, subject, sender, TIME,
    spam_level, size, sid, email ) AS

SELECT STRAIGHT_JOIN
      concat(CAST(mr.mail_id AS CHAR(255) charset utf8), 
             CAST(mr.partition_tag AS CHAR(255) charset utf8)) AS `id`,
      mr.mail_id,
      mr.partition_tag,
      mr.content,
      mr.rs,
      m.subject,
      m.from_addr AS sender,
      m.time_num AS `TIME`,
      m.spam_level,
      m.size,
      m.sid,
      maddr.email
   FROM
      msgrcpt mr
         JOIN msgs m
            ON mr.mail_id = m.mail_id
           AND mr.partition_tag = m.partition_tag
         JOIN maddr
            ON mr.rid = maddr.id
于 2012-07-03T14:05:26.937 に答える
-1

count()高速化するために主キー列を書き込みます。count(id)

于 2012-07-07T13:21:47.973 に答える