Mysql 如何强制mariaDB使用索引?

Mysql 如何强制mariaDB使用索引?,mysql,indexing,mariadb,explain,Mysql,Indexing,Mariadb,Explain,我正在尝试执行一个SQL查询。不幸的是,它不使用索引,而是进行表扫描 我已经创建了以下索引: 主要($phone,$$fc\u日期) idx$$fc\u状态\u详细信息 idx$$fc\u日期 idx$$fc\u状态 idx$$电话 此外,我复制了该表,但这也没有提供任何有用的结果 这是表结构: +--------------------+--------------+------+-----+---------+-------+ | Field | Type

我正在尝试执行一个SQL查询。不幸的是,它不使用索引,而是进行表扫描

我已经创建了以下索引:

  • 主要($phone,$$fc\u日期)
  • idx$$fc\u状态\u详细信息
  • idx$$fc\u日期
  • idx$$fc\u状态
  • idx$$电话
此外,我复制了该表,但这也没有提供任何有用的结果

这是表结构:

+--------------------+--------------+------+-----+---------+-------+
| Field              | Type         | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------+-------+
| $id                | varchar(100) | NO   |     | NULL    |       |
| $created_date      | varchar(100) | YES  |     | NULL    |       |
| $phone             | varchar(100) | NO   | PRI | NULL    |       |
| $source            | varchar(100) | YES  |     | NULL    |       |
| Orga               | varchar(100) | YES  |     | NULL    |       |
| Anrede             | varchar(100) | YES  |     | NULL    |       |
| Vorname            | varchar(100) | YES  |     | NULL    |       |
| Zuname             | varchar(100) | YES  |     | NULL    |       |
| Strasse            | varchar(100) | YES  |     | NULL    |       |
| PLZ                | varchar(100) | YES  |     | NULL    |       |
| Ort                | varchar(100) | YES  |     | NULL    |       |
| Geburtsdatum       | varchar(100) | YES  |     | NULL    |       |
| Email              | varchar(100) | YES  |     | NULL    |       |
| Zeitschrift        | varchar(100) | YES  |     | NULL    |       |
| Herkunft           | varchar(100) | YES  |     | NULL    |       |
| Zeitschrift_Titel  | varchar(100) | YES  |     | NULL    |       |
| telefon            | varchar(100) | YES  |     | NULL    |       |
| Stornogrund        | varchar(100) | YES  |     | NULL    |       |
| Storno             | varchar(100) | YES  |     | NULL    |       |
| Telefonnummer      | varchar(100) | YES  |     | NULL    |       |
| Postleitzahl       | varchar(100) | YES  |     | NULL    |       |
| Geburtsjahr        | varchar(100) | YES  |     | NULL    |       |
| $$fc_task          | varchar(100) | YES  |     | NULL    |       |
| $$fc_user          | varchar(100) | YES  |     | NULL    |       |
| $$fc_date          | varchar(100) | NO   | PRI | NULL    |       |
| $$fc_status        | varchar(100) | YES  | MUL | NULL    |       |
| $$fc_status_detail | varchar(100) | YES  | MUL | NULL    |       |
| $$qc_task          | varchar(100) | YES  |     | NULL    |       |
| $$qc_user          | varchar(100) | YES  |     | NULL    |       |
| $$qc_date          | varchar(100) | YES  |     | NULL    |       |
| $$qc_status        | varchar(100) | YES  |     | NULL    |       |
| $$qc_status_detail | varchar(100) | YES  |     | NULL    |       |
| $call_duration     | smallint(6)  | YES  |     | NULL    |       |
| $call_attempts     | smallint(6)  | YES  |     | NULL    |       |
+--------------------+--------------+------+-----+---------+-------+
以下是查询:

EXPLAIN SELECT
    count(*) as total,
    CONCAT(case when c1.$$fc_date < 240 then "short" else "long" end, "/", c1.$$fc_status, "/", c1.$$fc_status_detail) as ergebnis,
    sum(case when c2.$$fc_status = 'success' then 1 else 0 end)/ count(*) as c2_succes_rate
FROM
    contacts c1 FORCE INDEX (PRIMARY),
    contacts_copy c2
WHERE
    c1.$phone = c2.$phone
    and c1.$$fc_date < c2.$$fc_date
group by
    ergebnis
正如您在第1行中看到的,虽然它识别主键,但不使用它。问题是它扫描了200万次。行,查询至少持续5分钟


有人能解释一下,可能是什么问题吗?

您正在使用InnoDB,对吗?InnoDB次键(如
索引(电话)
)隐式包含
主键的列。因此,索引实际上是一个包含
(phone,fc\u date)
的BTree

接下来,我们注意到需要从
c2
fc_status
中添加另一列。因此,优化器研究了两种运行查询的方法。首先,请注意,这两种方法在索引中都有最佳列,并且它们的顺序都是最佳的

方案A:使用索引,然后在索引和数据之间来回跳转

方案B:做一个表格扫描,不需要来回扫描

优化器正确地选择了B

您可以有一个更好的索引,优化器很可能会选择它。而且速度会更快:

INDEX(phone, fc_date, fc_status)  -- in this order
这是“覆盖”,因为所有需要的列都存在。因此,不会有任何来回

我需要批评VARCHAR(100)
。这可能对日期非常不利,因为根据格式,日期可能无法正确排序


名字可能永远不会是100个字符;电子邮件可能会更长。等等,4个电话号码?有什么事吗?

请提供表格定义好吗?我的印象是,您正在尝试动态创建索引,这占用了您的时间。此外,如果没有这些,那么“调试”查询就很难了。我已经在我的帖子中包含了该结构。由于我们不需要事务,我已经从InnoDB切换到MyISAM引擎,但这没有帮助。我已将“innodb_buffer_pool_size”增加到“5G”,但这也没有帮助。您是否尝试过在c1上使用
加入联系人\u复制c2。$phone=c2。$phone和c1。$$fc_date
而不是where?@MarkoSeidenglanz see您能否提供示例数据和预期结果。。也许有更好的方法来重写具有相同结果但性能更好的查询。。此外,我们还必须了解您的MySQL版本,因为在MySQL 8.0中,获取连续记录更容易。。我们还可以更好地测试优化,因为我们有数据优化器计划,可以根据数据大小进行更改。非常喜欢您的解释(索引部分)!至于为什么一切都是varchar,我认为他只是太懒了,不愿意转换,毕竟,即使在示例查询中,他也会将
$$fc_status
字段与
'success'
进行比较,但他可能只是在表中有一个bool表示成功。他可能刚刚开始使用数据库,还没有认识到使用适当的数据类型更快,通常会产生更小的数据库。别用粗话吓唬他,他是新来的!这个答案确实有助于提高我对表格设计的理解。不幸的是,使用组合索引(电话、fc_日期、fc_状态)查询没有加快速度。我已将所有内容导入BigQuery。这就解决了问题。@MarkoSeidenglanz-您是否也删除了
力索引(主)
。我对“索引提示”的看法是:“它们今天可能有用,但明天可能会让事情变得更糟。”问题不在于索引,而在于糟糕的数据。有许多行带有
$phone=”“
,这会破坏整个查询。
INDEX(phone, fc_date, fc_status)  -- in this order