ここにいくつかのinnodbテーブルがあります。非常に頻繁に_insert,update,query
_です。
tn
は製品IDです
col
は製品のサブIDです
tindex
は製品の説明です。(ワードごとに保存)
date
は、strototime('now')
によって保存された製品追加日です
_CREATE TABLE IF NOT EXISTS `mytable` (
`tn` varchar(15) NOT NULL,
`col` smallint(2) NOT NULL,
`tindex` varchar(30) NOT NULL,
`date` int(10) NOT NULL,
KEY `date` (`date`),
KEY `tn` (`tn`),
KEY `tindex` (`tindex`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
_
サブIDに「防食剤」と「防水剤」という単語が含まれている一部の製品をクエリする方法
_SELECT *
FROM mytable a
WHERE tindex = 'anticorrosive'
AND EXISTS (
SELECT 1
FROM mytable
WHERE tn = a.tn
AND col = a.col
AND tindex = 'waterproof'
)
ORDER BY DATE
LIMIT 10
_
テーブル全体が本来_12,700,000
_行、_1.1GB
_、コスト__4.8356s
_、explianクエリget
_id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY a ref tn,tindex tindex 92 const 1173 Using where; Using filesort
2 DEPENDENT SUBQUERY mytable ref tn,tindex tn 47 production.a.tn 161 Using where
_
そして、これが_my.ini
_です。
_[mysqld]
character_set_server=utf8
skip-external-locking
skip-networking
key_buffer = 256M
tmp_table_size = 128M
max_connections = 1024
wait_timeout=10
back_log = 2048
key_buffer_size = 256M
max_allowed_packet = 2M
table_cache = 2048
table_open_cache = 1024
sort_buffer_size = 8M
read_buffer_size = 4M
net_buffer_length = 92K
read_rnd_buffer_size = 8M
myisam_sort_buffer_size = 256M
thread_cache = 512
query_cache_size= 256M
bulk_insert_buffer_size = 192M
ft_min_Word_len=2
innodb_buffer_pool_size = 512M
innodb_flush_log_at_trx_commit = 2
_
クエリを高速化するには?インデックスをやり直しますか?クエリコード?または_my.ini
_の値を変更します
PDATE 1インデックスキーを変更しようとしましたが、テーブルはまだ大きくなりましたが、今では_20mln
_行_2.2GB
_が必要です
_ALTER TABLE mytable ADD UNIQUE INDEX (tn,col,tindex);
ALTER TABLE mytable ADD INDEX (date);
_
クエリ1
_SELECT A.* FROM
(SELECT * FROM mytable WHERE tindex='words1') A
INNER JOIN
(SELECT tn,col FROM mytable WHERE tindex='words2') B
USING (tn,col) order by date limit 10
_
29.6278を使用
_id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 15674 Using temporary; Using filesort
1 PRIMARY <derived3> ALL NULL NULL NULL NULL 1716 Using where; Using join buffer
3 DERIVED mytable index NULL date 5 NULL 13918039 Using where; Using index
2 DERIVED mytable index NULL date 5 NULL 13918039 Using where; Using index
_
クエリ2
_SELECT * FROM mytable
WHERE tindex IN ('words1','words2')
GROUP BY tn,col HAVING COUNT(1)=2 order by date limit 10;
_
23.8711を使用
_id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE mytable index NULL date 5 NULL 19359399 Using where; Using index; Using temporary
_
いくつかのメモ:
PRIMARY KEY
がないのはなぜですか?date
のタイプがint
であり、date
またはdatetime
またはtimestamp
ではないのはなぜですか?date
と呼ばれるのはなぜですか?実際の質問、クエリの効率、(tindex, tn, col, date)
のインデックスは、他の提案よりもはるかに役立つと思います。また、主キーがなく、(tindex, tn, col)
が一意である(別の一意のインデックスを追加した)ため、私の提案は次のとおりです。
主キーを(tindex, tn, col)
として定義します。
ALTER TABLE mytable
DROP INDEX __the_name_of_the_unique_index, -- this is optional
ADD PRIMARY KEY (tindex, tn, col) ;
これには時間がかかります(そのため、両方の操作を1つのパスで実行することをお勧めします。)
次に、クエリとクエリの推奨されるすべての書き換えを測定できます(プライマリインデックスが使用されているかどうかを確認します)。
tindex
列はインデックスの最初の列であるため、tindex='anticorrosive'
のすべての行はインデックスの連続したページにあります(tindex='corrosive'
のすべての行は別の部分にあります)したがって、インデックスのこれらの2つの部分を読み取る(スキャンする)は、テーブル全体をスキャンするか、インデックス全体を2回スキャンする(mysqlが(tn, col, tindex)
インデックス。)
このインデックスを主キーにするもう1つの利点は、InnoDBが追加し、テーブルのクラスター化インデックスとして使用していた(非表示の)6バイトの列を削除できることです(主または一意の制約/インデックスを提供しなかったため) )そのため、テーブルの幅が狭くなりました。 (tindex, tn, col)
は、これからテーブルのクラスター化インデックスになります。これは、インデックスの2つの部分がスキャンされた後、date
値がクエリで使用できることも意味します。
JOINを使用する
_SELECT *
FROM mytable a
JOIN
mytable b
ON b.tn = a.tn
AND b.col = a.col
WHERE b.tindex = 'waterproof'
AND a.tindex = 'anticorrosive'
ORDER BY a.DATE
LIMIT 10
_
また、コンポジットindex(tn,col,tindex)
も役立ちます。
2つのアプローチがあります
相関サブクエリを破棄して、2つのサブクエリのJOINに置き換える必要があります
SELECT A.* FROM
(SELECT * FROM mytable WHERE tindex='anticorrosive') A
INNER JOIN
(SELECT tn,col FROM mytable WHERE tindex='waterproof') B
USING (tn,col);
製品の数によっては、いずれにしてもこれは長いクエリになります。
SELECT tn,col FROM mytable
WHERE tindex IN ('anticorrosive','waterproof')
GROUP BY tn,col HAVING COUNT(1)=2;
これはもっと似ているはずです(オーバーヘッドが少ない)
このインデックスを追加してください
ALTER TABLE mytable ADD UNIQUE INDEX (tn,col,tindex);
これにより、すべての(tn、col)に一意のtindex値のみが含まれるようになります。
rows
カラムはmysqlがどの行(1173&47)を処理する必要があるかを正確に取得することを意味するため、あなたのクエリはすでにmysqlによって実行されていると思います。
あなたの問題はORDER BYです:
それを修正するには、sort_buffer_size
から1024M
一意の別のインデックスも試してください:(tindex、date)または(date、tindex)