查询性能 - 'Left join is null' 对比 'Not exists select'

Query performance - 'Left join is null' vs 'Not exists select'

我对要执行的查询有疑问,但我不知道什么是最佳性能。我需要让所有单词排除与 table wordfilter 相关的单词。

查询的输出是正确的,但也许有更好的解决方案。我几乎 none 了解有关查询计划的知识,我现在正在努力理解它。

SELECT CONCAT(SPACE(1), UCASE(stocknews.word.word), SPACE(1)) AS word, stocknews.word.language 
FROM stocknews.word 
WHERE NOT EXISTS (SELECT word_id FROM stocknews.wordfilter WHERE stocknews.word.id = word_id) 
AND user_id = 1

+----+--------------+------------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type  | table      | type  | possible_keys | key     | key_len | ref   | rows | extra       |
+----+--------------+------------+-------+---------------+---------+---------+-------+------+-------------+
|  1 | PRIMARY      | word       | ref   | user_id       | user_id | 4       | const | 843  | Using where |
|  2 | MATERIALIZED | wordfilter | index | PRIMARY       | PRIMARY | 756     |       | 16   | Using index |
+----+--------------+------------+-------+---------------+---------+---------+-------+------+-------------+

反对

SELECT CONCAT(SPACE(1), UCASE(stocknews.word.word), SPACE(1)) AS word, stocknews.word.language 
FROM stocknews.word 
LEFT JOIN stocknews.wordfilter ON stocknews.word.id = stocknews.wordfilter.word_id 
WHERE stocknews.wordfilter.word_id IS NULL AND user_id = 1

+----+-------------+------------+------+---------------+---------+---------+---------+------+--------------------------------------+
| id | select_type | table      | type | possible_keys | key     | key_len | ref     | rows | extra                                |
+----+-------------+------------+------+---------------+---------+---------+---------+------+--------------------------------------+
|  1 | SIMPLE      | word       | ref  | user_id       | user_id | 4       | const   | 843  |                                      |
|  1 | SIMPLE      | wordfilter | ref  | PRIMARY       | PRIMARY | 4       | word.id | 1    | Using where; Using index; Not exists |
+----+-------------+------------+------+---------------+---------+---------+---------+------+--------------------------------------+

欢迎任何帮助!有解释就好了。

编辑:

对于查询 1:

+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Handler_commit             | 1     |
| Handler_delete             | 0     |
| Handler_discover           | 0     |
| Handler_external_lock      | 0     |
| Handler_icp_attempts       | 0     |
| Handler_icp_match          | 0     |
| Handler_mrr_init           | 0     |
| Handler_mrr_key_refills    | 0     |
| Handler_mrr_rowid_refills  | 0     |
| Handler_prepare            | 0     |
| Handler_read_first         | 1     |
| Handler_read_key           | 1044  |
| Handler_read_last          | 0     |
| Handler_read_next          | 859   |
| Handler_read_prev          | 0     |
| Handler_read_rnd           | 0     |
| Handler_read_rnd_deleted   | 0     |
| Handler_read_rnd_next      | 0     |
| Handler_rollback           | 0     |
| Handler_savepoint          | 0     |
| Handler_savepoint_rollback | 0     |
| Handler_tmp_update         | 0     |
| Handler_tmp_write          | 215   |
| Handler_update             | 0     |
| Handler_write              | 0     |
+----------------------------+-------+
25 rows in set (0.00 sec)

对于查询 2:

+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Handler_commit             | 1     |
| Handler_delete             | 0     |
| Handler_discover           | 0     |
| Handler_external_lock      | 0     |
| Handler_icp_attempts       | 0     |
| Handler_icp_match          | 0     |
| Handler_mrr_init           | 0     |
| Handler_mrr_key_refills    | 0     |
| Handler_mrr_rowid_refills  | 0     |
| Handler_prepare            | 0     |
| Handler_read_first         | 0     |
| Handler_read_key           | 844   |
| Handler_read_last          | 0     |
| Handler_read_next          | 843   |
| Handler_read_prev          | 0     |
| Handler_read_rnd           | 0     |
| Handler_read_rnd_deleted   | 0     |
| Handler_read_rnd_next      | 0     |
| Handler_rollback           | 0     |
| Handler_savepoint          | 0     |
| Handler_savepoint_rollback | 0     |
| Handler_tmp_update         | 0     |
| Handler_tmp_write          | 0     |
| Handler_update             | 0     |
| Handler_write              | 0     |
+----------------------------+-------+

这两个公式似乎势均力敌。 (其他一些示例可能会显示更明显的赢家。)

根据 HANDLER 值:查询 1 做了更多 read_keys 和一些写作(与 MATERIALIZED 一起)。其他数字大致相同。因此,我得出结论,查询 1 较慢——尽管可能慢得不足以产生很大的不同。

我投票支持 LEFT JOIN 作为更好的查询模式(在本例中)