!!!union

本文详细介绍了C++中的联合类型(union)及其初始化方式,并通过实例展示了如何使用判别式来判断联合体中存储的数据类型。同时,文章还探讨了在结构体中嵌套联合体时的常见用法。

联合判别式

联合只能用第一个成员类型的值进行初始化。且初始化必须放在一个大括号里面.

  • 联合体是所有的成员都共用一块内存,如下
#include <iostream>

using namespace std;

union s
{
    int a;
    char c;
};

int main()
{
    union s s1 = {97};   //如果将char,和int调换位置,则由于内存中高24位不确定,可能出现乱码

    cout << s1.a << endl;
    cout << s1.c << endl;
}

union的判别式(discriminant)

在使用联合对象时,我们往往得确定union对象当前存储的是什么类型的值,所以,更常见的用法是使用 union的判别式(discriminant).

#include <iostream>

using namespace std;

enum T{INT,CHAR};

struct Data{
    T type;

    union {
        char c;//1
        int a;// 4
    //}val;
    };
};

/*void out_data(Data *p) //结构体中的联合体有变量val
{
    if(p->type == INT)
        cout << p->val.a << endl;
    else if(p->type == CHAR)
        cout << p->val.c << endl;
}
*/

void out_data(Data *p)  //结构体中的联合体没有声明变量,则直接引用
{
    if(p->type == INT)
        cout << p->a << endl;
    else if(p->type == CHAR)
        cout << p->c << endl;
}
int main()
{
    Data d;
    d.type = CHAR;
    d.c = 97;

    out_data(&d);
    return 0;
}
<think> 我们正在讨论MySQL中对不等于操作(!=)的优化方法。根据引用材料,我们可以总结出以下几点: 1. 引用[1]提到,对于IN操作,如果数值较多,消耗较大,建议使用BETWEEN或连接替换。虽然这里讨论的是IN,但思路可以借鉴:即考虑用其他操作替代。 2. 引用[2]中提到OR改UNION效率高,并且提到了覆盖索引和条件优化。这提示我们,对于不等于操作,可能也可以通过改写查询条件来利用索引。 3. 引用[3]介绍了<=>操作符,它可以在与NULL比较时返回0或1,而不像=运算符那样返回NULL。注意,!=操作符在与NULL比较时也会返回NULL,因此需要小心。 优化思路: 1. 避免全表扫描:当使用!=时,如果列上有索引,MySQL可能不会使用索引(因为!=通常要扫描大部分数据)。我们可以考虑改写查询,使其能够利用索引。 2. 考虑NULL值:当列允许为NULL时,条件`column != value`不会包含NULL的行(因为NULL与任何值比较都是NULL,条件不成立)。如果我们也需要NULL的行,则需要额外加上`OR column IS NULL`。 3. 改写查询:有时候可以将!=条件改写为大于(>)和小于(<)的组合,这样可能使用索引。例如,`column != 5` 可以改写为 `column < 5 OR column > 5`。但是,这样改写后,如果列上有索引,MySQL可能会使用索引合并(index merge)来优化,但索引合并并不总是高效的。 具体优化方法: 方法1:使用大于和小于代替不等于(注意NULL值) 原始查询:`SELECT * FROM table WHERE column != value;` 改写为:`SELECT * FROM table WHERE column < value OR column > value;` 注意:如果列允许为NULL,并且需要包含NULL的行,则改为:`SELECT * FROM table WHERE column < value OR column > value OR column IS NULL;` 但是,这种改写并不总是更好。因为OR条件可能会导致无法使用索引,或者即使使用索引合并,其效率也可能不如全表扫描(取决于数据分布)。因此需要根据实际情况测试。 方法2:覆盖索引 如果查询的列都包含在索引中,那么即使使用!=,也可能使用索引扫描(因为只需要扫描索引,而不需要回表)。例如,有一个索引(column),那么查询`SELECT column FROM table WHERE column != value`就可以使用覆盖索引。 方法3:避免在索引列上使用不等于(如果数据分布不均匀) 如果索引列的值分布不均匀,例如某个值占据绝大多数,那么使用!=(排除这个值)就会返回少量数据,此时使用索引可能更高效。反之,如果排除的值很少,那么使用!=将导致全表扫描,此时可能不如考虑其他方法。 方法4:使用UNION改写(类似于OR改UNION) 对于方法1中用OR拆分的情况,我们可以进一步改写为UNION: 原始:`SELECT * FROM table WHERE column != value;` 改写为: ```sql SELECT * FROM table WHERE column < value UNION ALL SELECT * FROM table WHERE column > value; ``` 注意:这里使用UNION ALL而不用UNION(避免去重),因为两个条件互斥。同样,如果需要包含NULL,再加一个: ```sql SELECT * FROM table WHERE column < value UNION ALL SELECT * FROM table WHERE column > value UNION ALL SELECT * FROM table WHERE column IS NULL; ``` 这样,如果每个部分都能使用索引,那么效率可能更高。 方法5:考虑使用NOT EXISTS(特别是在子查询中) 当在子查询中使用不等于时,有时可以用NOT EXISTS代替。例如: 原始:`SELECT * FROM table1 WHERE id NOT IN (SELECT id FROM table2);` 可以改写为:`SELECT * FROM table1 t1 WHERE NOT EXISTS (SELECT 1 FROM table2 t2 WHERE t1.id=t2.id);` 注意:NOT IN在遇到子查询返回NULL时会有问题(整个结果为空),而NOT EXISTS则不会。 注意事项: - 任何优化都需要实际测试,使用EXPLAIN查看执行计划。 - 注意NULL值的影响,确保查询结果正确。 示例: 假设有一张表`orders`,有一个字段`status`(允许为NULL),我们想查询状态不是1的订单。 原始查询:`SELECT * FROM orders WHERE status != 1;` -- 这会排除NULL的行 如果需要包含NULL:`SELECT * FROM orders WHERE status != 1 OR status IS NULL;` 我们可以尝试改写为: 方法1:大于和小于(针对非NULL) `SELECT * FROM orders WHERE status < 1 OR status > 1 OR status IS NULL;` 然后检查执行计划。 方法2:使用UNION ALL(假设status上有索引): ```sql SELECT * FROM orders WHERE status < 1 UNION ALL SELECT * FROM orders WHERE status > 1 UNION ALL SELECT * FROM orders WHERE status IS NULL; ``` 结论: 优化!=操作的关键是尝试将其转换为能够利用索引的查询。具体方法包括使用范围查询(<和>)、使用UNION拆分、使用覆盖索引等,同时要注意NULL值的处理。 根据引用[2],我们还可以考虑覆盖索引,即如果只需要索引列,则使用覆盖索引扫描。 引用标识: [^1] 提到了IN操作的优化,可以借鉴思路。 [^2] 提到了OR改UNION,以及覆盖索引。 [^3] 提醒我们注意NULL值的处理。 因此,在回答中,我们将综合这些方法。 生成相关问题: 1. MySQL中使用!=操作符时,如何避免全表扫描? 2. 在MySQL中,如何处理NULL值对不等于操作的影响? 3. 如何通过覆盖索引优化不等于查询? 4. 使用UNION改写!=查询在什么情况下更高效? </think> ### MySQL 中优化不等于 (`!=`) 操作的解决方案 在 MySQL 中,`!=`(不等于)操作可能导致性能问题,尤其在大型数据集或复杂查询中。以下是优化策略,结合索引使用、查询重写和特殊值处理: --- #### 1. **优先使用覆盖索引** [^2] 当查询仅需索引字段时,避免回表操作: ```sql -- 优化前(需要回表) SELECT * FROM orders WHERE status != 'completed'; -- 优化后(覆盖索引) SELECT order_id, status FROM orders WHERE status != 'completed'; -- status字段需建立索引 ``` **效果**:减少 I/O 操作,执行计划显示 `Using index`。 --- #### 2. **改写为范围查询** [^1] 连续数值时,用 `BETWEEN` 或范围查询替代: ```sql -- 优化前 SELECT * FROM products WHERE price != 100; -- 优化后(假设价格是连续值) SELECT * FROM products WHERE price < 100 OR price > 100; -- 可能触发范围索引扫描 ``` --- #### 3. **处理 `NULL` 值的特殊技巧** [^3] `!=` 会忽略 `NULL` 值,需显式处理: ```sql -- 查找非管理员用户(包含NULL) SELECT * FROM users WHERE role != 'admin' OR role IS NULL; -- 显式包含NULL ``` 使用 `<=>` 安全比较: ```sql SELECT * FROM users WHERE NOT role <=> 'admin'; -- 等价于 role != 'admin' OR role IS NULL ``` --- #### 4. **`NOT EXISTS` 替代子查询** [^2] 子查询中的 `!=` 可优化为 `NOT EXISTS`: ```sql -- 优化前 SELECT * FROM customers WHERE id NOT IN (SELECT customer_id FROM blacklist); -- 优化后 SELECT * FROM customers c WHERE NOT EXISTS ( SELECT 1 FROM blacklist b WHERE b.customer_id = c.id ); ``` --- #### 5. **分治策略:`UNION` 拆分复杂条件** [^2] ```sql -- 优化前(单索引难覆盖) SELECT * FROM logs WHERE type != 'error' AND source != 'api'; -- 优化后(拆分利用独立索引) SELECT * FROM logs WHERE type != 'error' UNION SELECT * FROM logs WHERE source != 'api'; ``` --- ### 性能验证工具 执行优化前后对比: ```sql EXPLAIN SELECT ...; -- 检查索引使用 SHOW PROFILES; -- 分析执行耗时 ``` > **关键原则**: > - 对 `!=` 字段建立索引 > - 避免全表扫描(`type: ALL`) > - 优先覆盖索引减少 I/O > - 显式处理 `NULL` 值[^3] --- ### 相关问题 1. MySQL 中如何优化 `NOT IN` 子查询的性能? 2. 覆盖索引在哪些场景下可以提升查询效率?[^2] 3. 使用 `<=>` 操作符处理 `NULL` 值有哪些注意事项?[^3] 4. 如何通过执行计划(`EXPLAIN`)诊断索引失效问题? 5. 大数据量表中使用 `UNION` 替代 `OR` 的条件限制是什么?[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值