【问题标题】:How can I index these queries?如何索引这些查询?
【发布时间】:2017-06-27 07:52:23
【问题描述】:

我对我要做的索引有点困惑。

首先,我使用的是 4 列索引,如下所示:

索引名称 - advanced_query

将在索引中使用列 - 标题、类别 1、类别 2、类别 3

索引代码

ALTER TABLE table_name ADD INDEX advanced_query (`title`, `cat_1`, `cat_2`, `cat_3`, `date_posted`)

好的,这就是(据我了解)它的工作方式:

  • title 的查询将使用索引。
  • cat_1 的查询将使用索引。
  • cat_2 的查询将使用索引。
  • cat_3 的查询将使用索引。所以我会为它创建一个不同的索引。
  • title,cat_1的查询将使用索引。
  • title,cat_1,cat_2的查询将使用索引。
  • title、cat_1、cat_2、cat_3的查询将使用索引。
  • title,cat_1,cat_3的查询将使用索引。
  • title,cat_2的查询将使用索引。
  • title,cat_2,cat_3的查询将使用索引。
  • title,cat_3的查询将使用索引。
  • cat_1, cat_2 的查询将使用索引。
  • cat_1、cat_2、cat_3的查询将使用索引。
  • cat_1, cat_2 的查询将使用索引。
  • cat_1, cat_3 的查询将使用索引。

TL;DR

所以在这个索引中,只有 cat_3 的查询 不会从中受益,对吧?谢谢!

问答

我在做什么查询?搜索帖子(它的标题和 3 个不同的类别)

桌子的尺寸是多少?少于 2000 行

表的结构?

CREATE TABLE `post_lists` (
 `id` int(100) NOT NULL AUTO_INCREMENT,
 `users_id` varchar(100) NOT NULL,
 `code` varchar(255) NOT NULL,
 `date_posted` datetime NOT NULL,
 `date_updated` datetime NOT NULL,
 `title` varchar(255) NOT NULL,
 `cat_1` varchar(255) NOT NULL,
 `cat_3_code` varchar(255) NOT NULL,
 `details` varchar(10000) NOT NULL,
 `cat_2` varchar(255) NOT NULL,
 `cat_3` varchar(255) NOT NULL,
 UNIQUE KEY `id` (`id`),
 KEY `date_posted` (`date_posted`),
 KEY `code` (`urlcode`),
 KEY `users_id_date_posted` (`users_id`,`date_posted`),
 KEY `title_date_posted` (`title`,`date_posted`),
 KEY `cat_1_date_posted` (`cat_1`,`date_posted`)
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=latin1

这张桌子会使用多少次?大多数时候。这是高级搜索功能,不像基本搜索那样频繁。

这就是我实际使用索引的方式。

示例表

title | cat_1 | cat_2 | cat_3 | date_posted

我的查询很简单:

  1. 标题

    SELECT * FROM tbl_name WHERE title LIKE %title% ORDER BY date_posted DESC

  2. 标题 + cat_1

    SELECT * FROM tbl_name WHERE title LIKE %title% AND cat_1 = 'cat_1' ORDER BY date_posted DESC

  3. 标题 + cat_1 + cat_2

    SELECT * FROM tbl_name WHERE title LIKE %title% AND cat_1 = 'cat_1' AND cat_2 = 'cat_2' ORDER BY date_posted DESC

  4. title + cat_1 + cat_2 + cat_3

    SELECT * FROM tbl_name WHERE title LIKE %title% AND cat_1 = 'cat_1' AND cat_2 = 'cat_2' AND cat_3 = 'cat_3' ORDER BY date_posted DESC

  5. 标题 + cat_1 + cat_3

    SELECT * FROM tbl_name WHERE title LIKE %title% AND cat_1 = 'cat_1' and cat_3 = 'cat_3' ORDER BY date_posted DESC

  6. 标题 + cat_2

    SELECT * FROM tbl_name WHERE title LIKE %title% AND cat_2 = 'cat_2' ORDER BY date_posted DESC

  7. 标题 + cat_2 + cat_3

    SELECT * FROM tbl_name WHERE title LIKE %title% AND cat_2 = 'cat_2' AND cat_3 = 'cat_3' ORDER BY date_posted DESC

  8. 标题 + cat_3

    SELECT * FROM tbl_name WHERE title LIKE %title% AND cat_3 = 'cat_3' ORDER BY date_posted DESC

  9. cat_1

    SELECT * FROM tbl_name WHERE cat_1 = 'cat_1' ORDER BY date_posted DESC

  10. cat_1 + cat_2

    SELECT * FROM tbl_name WHERE cat_1 = 'cat_1' AND cat_2 = 'cat_2' ORDER BY date_posted DESC

  11. cat_1 + cat_2 + cat_3

    SELECT * FROM tbl_name WHERE cat_1 = 'cat_1' AND cat_2 = 'cat_2' AND cat_3 = 'cat_3' ORDER BY date_posted DESC

  12. cat_1 + cat_3

    SELECT * FROM tbl_name WHERE cat_1 = 'cat_1' AND cat_3 = 'cat_3' ORDER BY date_posted DESC

  13. cat_2

    SELECT * FROM tbl_name WHERE cat_2 = 'cat_2' ORDER BY date_posted DESC

  14. cat_2 + cat_3

    SELECT * FROM tbl_name WHERE cat_2 = 'cat_2' ORDER BY date_posted DESC

  15. cat_3

    SELECT * FROM tbl_name WHERE cat_3 = 'cat_3' ORDER BY date_posted DESC

如何查询?

编辑

嗨,我阅读并搜索了全文搜索,我正在考虑使用它(在基本搜索中)而不是 LIKE %wildcard% 并将其应用于 titledetails,我的问题是我希望他们排序ORDER BY date_posted DESC,那么我应该在全文搜索中添加date_posted还是创建一个单独的索引?

【问题讨论】:

  • 要了解您的查询是否使用您的索引,您应该在将EXPLAIN 添加到它们的开头之后运行它们中的每一个,所以EXPLAIN SELECT * ... 也许将解释的输出添加到您的问题中,请注意,如果您在开头使用通配符,则索引不适用于标题,因此'%title%' 不会使用索引,但'title''titl%' 会。
  • @FMashiro 我明白了,所以我将使用一个'%'而不是双倍%?谢谢。
  • 另外,当用户请求Structure of the table ? 时,他们通常意味着他们想要SHOW CREATE TABLE tablename 输出或至少是数据类型
  • 不一定,因为如果您在末尾使用单个通配符,'itle%' 将不再匹配 'title'。请注意,我只是提到它不会使用索引。
  • 但是你说'title%' 会使用索引对吗?所以像这样SELECT * FROM tbl WHERE title LIKE 'title%' AND cat_1 = 'cat_1 and so on...'这会使用索引吗?

标签: mysql


【解决方案1】:

我认为您的问题的“答案”有点复杂,您对索引使用的假设并不总是正确的。

简短的回答是:“视情况而定”。

实际上,索引的使用取决于几个因素:表中的记录数、索引结构、请求的字段、查询中的条件、统计信息。

1) 记录数:如果它很小,也许数据库引擎决定不使用索引(特别是如果你写 SELECT * of SELECT --several columns in table not in index --)。

如果您仅选择索引中的部分或全部列,则可以使用索引(也不考虑 WHERE 条件)。

2) 索引结构:正如您所指出的,它是相关的。此外,可以“使用”索引有两种不同的主要方式:扫描和查找。寻找是最有效的。在大多数情况下,如果您以与编写它们相同的顺序查找索引中的列:例如。从您的表中选择标题,其中标题如“ABC%”)。注意:如果你写了 LIKE '%ABC%' 它不能进行搜索,而是进行扫描。 (扫描意味着 db 必须从头到尾查找整个索引,而通过搜索,他会直接转到相关页面,就像您在电话簿中使用姓氏查找某人的电话号码一样)。

3) 请求的字段:您应该考虑如果您编写 SELECT *(正如我在上面指出的,数据库引擎可能会决定使用全表扫描)

4) 查询条件。

5) 统计:数据库引擎写入数据和索引的统计信息(记录数、结构等)。如果它们没有更新,它可能会以“错误”的方式使用或不使用索引。

----- 更新:简单(不详尽...)演示

实际上(对于这个小数据,我不得不评论您的 KEY 'title_date_posted' 以使其在某些情况下使用“advanced_query”索引:否则它似乎会尝试使用它; 正如我告诉过你的,数据库引擎会在内部决定使用什么索引)。

在 rextester.com 上完成测试:

##DROP TABLE post_lists;

CREATE TABLE `post_lists` (
 `id` int(100) NOT NULL AUTO_INCREMENT,
 `users_id` varchar(100) NOT NULL,
 `code` varchar(255) NOT NULL,
 `date_posted` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
 `date_updated` datetime NOT NULL  DEFAULT CURRENT_TIMESTAMP,
 `title` varchar(255) NOT NULL,
 `cat_1` varchar(255) NOT NULL,
 `cat_3_code` varchar(255) NOT NULL,
 `details` varchar(10000) NULL,
 `cat_2` varchar(255) NOT NULL,
 `cat_3` varchar(255) NOT NULL,
 UNIQUE KEY `id` (`id`)
    , KEY `date_posted` (`date_posted`)
    , KEY `code` (`code`)
    , KEY `users_id_date_posted` (`users_id`,`date_posted`)
    ##, KEY `title_date_posted` (`title`,`date_posted`)
    , KEY `cat_1_date_posted` (`cat_1`,`date_posted`)
)   DEFAULT CHARSET=latin1;

ALTER TABLE post_lists ADD INDEX advanced_query (`title`, `cat_1`, `cat_2`, `cat_3`, `date_posted`);

INSERT INTO post_lists (users_id, code, title, cat_1, cat_3_code, details, cat_2, cat_3) VALUES ('123', 'ABC', 'TITLE1', '001','C3','blah blah blah', '002', '003');
INSERT INTO post_lists (users_id, code, title, cat_1, cat_3_code, details, cat_2, cat_3) VALUES ('456', 'ABC', 'TITLE2', '002','C32','blah blah blah', '0021', '0031');

SELECT * FROM post_lists;

EXPLAIN SELECT * FROM post_lists WHERE title = 'TITLE1'; 
EXPLAIN SELECT title FROM post_lists  WHERE title = 'TITLE1'; 
EXPLAIN SELECT title, cat_1, cat_3, code FROM post_lists  WHERE title = 'TITLE1'; 
EXPLAIN SELECT title, cat_1, cat_3 FROM post_lists  WHERE title = 'TITLE1'; 

DROP TABLE post_lists;

输出:

    +----+----+----------+------+---------------------+---------------------+--------+-------+------------+----------------+-------+-------+
|    | id | users_id | code |     date_posted     |    date_updated     | title  | cat_1 | cat_3_code |    details     | cat_2 | cat_3 |
+----+----+----------+------+---------------------+---------------------+--------+-------+------------+----------------+-------+-------+
|  1 |  1 |      123 | ABC  | 27.06.2017 11:02:16 | 27.06.2017 11:02:16 | TITLE1 |   001 | C3         | blah blah blah |   002 |   003 |
|  2 |  2 |      456 | ABC  | 27.06.2017 11:02:16 | 27.06.2017 11:02:16 | TITLE2 |   002 | C32        | blah blah blah |  0021 |  0031 |
+----+----+----------+------+---------------------+---------------------+--------+-------+------------+----------------+-------+-------+

+----+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------+
|    | id | select_type |   table    | partitions | type | possible_keys  |      key       | key_len |  ref  | rows | filtered | Extra |
+----+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------+
|  1 |  1 | SIMPLE      | post_lists | NULL       | ref  | advanced_query | advanced_query |     257 | const |    1 |      100 | NULL  |
+----+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------+



+----+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------------+
|    | id | select_type |   table    | partitions | type | possible_keys  |      key       | key_len |  ref  | rows | filtered |    Extra    |
+----+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------------+
|  1 |  1 | SIMPLE      | post_lists | NULL       | ref  | advanced_query | advanced_query |     257 | const |    1 |      100 | Using index |
+----+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------------+

+----+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------+
|    | id | select_type |   table    | partitions | type | possible_keys  |      key       | key_len |  ref  | rows | filtered | Extra |
+----+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------+
|  1 |  1 | SIMPLE      | post_lists | NULL       | ref  | advanced_query | advanced_query |     257 | const |    1 |      100 | NULL  |
+----+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------+


+----+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------------+
|    | id | select_type |   table    | partitions | type | possible_keys  |      key       | key_len |  ref  | rows | filtered |    Extra    |
+----+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------------+
|  1 |  1 | SIMPLE      | post_lists | NULL       | ref  | advanced_query | advanced_query |     257 | const |    1 |      100 | Using index |
+----+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------------+

【讨论】:

  • 如果我不使用*,但选择了超过一半的列,它也会进行全表扫描吗?
  • 我只选择了3列但是mysql没有使用索引。
  • 查看更新的答案(我不太喜欢删除投票的人...)
  • 是的,我删除了那个索引。
  • 我建议找一个好的教程(es. Google:SQL INDEX BEST PRACTICES)--> toadworld.com/platforms/sql-server/w/wiki/…(这是针对MSSQL,但有些东西对其他数据库有效)或MYSQL INDEX最佳实践 --> dba.stackexchange.com/questions/135563/…
猜你喜欢
  • 1970-01-01
  • 2021-08-31
  • 1970-01-01
  • 1970-01-01
  • 2022-12-16
  • 2019-10-03
  • 2011-04-10
  • 2016-06-03
  • 1970-01-01
相关资源
最近更新 更多