s, employees e WHERE s.emp_no = e.emp_no \G *************************** 1. row *************************** EXPLAIN: -> Nested loop inner join (cost=509454 rows=3.1e+6) (actual time=0.747..3140 rows=2.84e+6 loops=1) -> Table scan on e (cost=30471 rows=299645) (actual time=0.499..207 rows=300024 loops=1) -> Index lookup on s using PRIMARY (emp_no=e.emp_no) (cost=0.563 rows=10.4) (actual time=0.00643..0.00904 rows=9.48 loops=300024) 1 row in set (3.65 sec) > EXPLAIN FORMAT=TREE SELECT * FROM salaries s, employees e WHERE s.emp_no = e.emp_no \G *************************** 1. row *************************** EXPLAIN: -> Nested loop inner join (cost=510750 rows=3.1e+6) -> Table scan on e (cost=30504 rows=299645) -> Index lookup on s using PRIMARY (emp_no=e.emp_no) (cost=0.567 rows=10.4) 1 row in set (0.00 sec)
• インデックスヒント https://dev.mysql.com/doc/refman/8.0/ja/index-hints.html • Optimizer Hints https://dev.mysql.com/doc/refman/8.0/ja/optimizer-hints.html SELECT * FROM t1 USE INDEX (i1) IGNORE INDEX FOR ORDER BY (i2) ORDER BY a;
• WHERE col1 = xxx AND col2 = xxx • 効かない条件 • WHERE col2 = xxx CREATE INDEX idx ON tbl (col1, col2) CREATE INDEX idx ON tbl (col2, col1) • 効く条件 • WHERE col2 = xxx • WHERE col1 = xxx AND col2 = xxx • 効かない条件 • WHERE col1 = xxx
LIMIT 句が深い • 2. WHERE条件にマッチするレコードがなかなか見つからない SELECT * FROM sbtest1 WHERE d < '2014-10-01' ORDER BY c LIMIT 1000000, 10; SELECT * FROM people WHERE age > 200 ORDER BY height LIMIT 10;
• どっちの処理を最適化する? SELECT * FROM sbtest1 WHERE d < '2014-10-01' ORDER BY c LIMIT 10; インデックス対象 動き WHERE 狙い のインデックス カラム d d < '2014-10-01' を満たすレコードの検索をインデックスで効率 化。条件を満たすレコードを抽出してからソートし、上位10件のみ 返す。 ORDER BY 狙い のインデックス カラム c インデックスを使って、ソートを最適化(スキップ)。カラム c の順に レコードを確認し、d < '2014-10-01' を満たすかチェック。10件集 まったら、処理完了。 ※ 厳密にいうとインデックスマージにより複数使われる場合もある
MySQL 5.7 以前はASCのみ(DESCでも無視して、ASCで作成) a h … a-p r-z r … z … … z r … z-r p-a h … a … … CREATE INDEX idx_col1 ON tbl(col1 ASC) CREATE INDEX idx_col1 ON tbl(col1 DESC)
WHERE hire_date >= '1995-01-01' SELECT COUNT(*) FROM salaries sal WHERE sal.salary >= 133000 SELECT emp.emp_no, emp.first_name, sal.salary FROM employees emp INNER JOIN salaries sal WHERE emp.emp_no = sal.emp_no AND emp.hire_date >= '1995-01-01' AND sal.salary >= 133000
WHERE hire_date >= '1995-01-01' SELECT COUNT(*) FROM salaries sal WHERE sal.salary >= 150000 SELECT emp.emp_no, first_name, salary FROM employees emp INNER JOIN salaries sal WHERE emp.emp_no = sal.emp_no AND emp.hire_date >= '1990-01-01' AND sal.salary >= 150000 34000 件 1000 件
execute(“SELECT id FROM tbl WHERE expired < NOW() and flag = 0 ORDER BY id”) for (i = 0; i < len(rows); i = i + 50) execute(“DELETE FROM tbl WHERE id IN (:id1, :id2, :id3, :id4, :id5, …)”)