精华内容
下载资源
问答
  • MySQL 优化器原来是这样工作

    千次阅读 2020-07-02 14:55:35
    MySQL 优化器使用基于成本的优化方式(Cost-based Optimization),利用内置的成本模型和数据字典信息以及存储引擎的统计信息决定使用哪些步骤实现查询语句,也就是查询计划。同时,MySQL 为我们提供了控制优化器的...

    大家好,我是只谈技术不剪发的 Tony 老师。我们在 MySQL 体系结构中介绍了 MySQL 的服务器逻辑结构,其中查询优化器(optimizer)负责生成 SQL 语句的执行计划,是决定查询性能的一个关键组件。本文将会深入分析 MySQL 优化器工作的原理以及如何控制优化器来实现 SQL 语句的优化。

    优化器概述

    MySQL 优化器使用基于成本的优化方式(Cost-based Optimization),以 SQL 语句作为输入,利用内置的成本模型和数据字典信息以及存储引擎的统计信息决定使用哪些步骤实现查询语句,也就是查询计划。

    optimizer
    查询优化和地图导航的概念非常相似,我们通常只需要输入想要的结果(目的地),优化器负责找到最有效的实现方式(最佳路线)。需要注意的是,导航并不一定总是返回最快的路线,因为系统获得的交通数据并不可能是绝对准确的;与此类似,优化器也是基于特定模型、各种配置和统计信息进行选择,因此也不可能总是获得最佳执行方式。

    从高层次来说,MySQL Server 可以分为两部分:服务器层以及存储引擎层。其中,优化器工作在服务器层,位于存储引擎 API 之上。优化器的工作过程从语义上可以分为四个阶段:

    1. 逻辑转换,包括否定消除、等值传递和常量传递、常量表达式求值、外连接转换为内连接、子查询转换、视图合并等;
    2. 优化准备,例如索引 ref 和 range 访问方法分析、查询条件扇出值(fan out,过滤后的记录数)分析、常量表检测;
    3. 基于成本优化,包括访问方法和连接顺序的选择等;
    4. 执行计划改进,例如表条件下推、访问方法调整、排序避免以及索引条件下推。

    逻辑转换

    MySQL 优化器首先可能会以不影响结果的方式对查询进行转换,转换的目标是尝试消除某些操作从而更快地执行查询。例如(数据来源):

    mysql> explain
        -> select *
        -> from employee
        -> where salary > 10000 and 1=1;
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
    | id | select_type | table    | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | employee | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   25 |    33.33 | Using where |
    +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    
    mysql> show warnings\G
    *************************** 1. row ***************************
      Level: Note
       Code: 1003
    Message: /* select#1 */ select `hrdb`.`employee`.`emp_id` AS `emp_id`,`hrdb`.`employee`.`emp_name` AS `emp_name`,`hrdb`.`employee`.`sex` AS `sex`,`hrdb`.`employee`.`dept_id` AS `dept_id`,`hrdb`.`employee`.`manager` AS `manager`,`hrdb`.`employee`.`hire_date` AS `hire_date`,`hrdb`.`employee`.`job_id` AS `job_id`,`hrdb`.`employee`.`salary` AS `salary`,`hrdb`.`employee`.`bonus` AS `bonus`,`hrdb`.`employee`.`email` AS `email` from `hrdb`.`employee` where (`hrdb`.`employee`.`salary` > 10000.00)
    1 row in set (0.00 sec)
    

    显然,查询条件中的 1=1 是完全多余的。没有必要为每一行数据都执行一次计算;删除这个条件也不会影响最终的结果。执行EXPLAIN语句之后,通过SHOW WARNINGS命令可以查看逻辑转换之后的 SQL 语句,从上面的结果可以看出 1=1 已经不存在了。

    📝关于 MySQL 执行计划和 EXPLAIN 语句的详细介绍可以参考这篇文章

    我们也可以通过优化器跟踪进一步了解优化器的执行过程,例如:

    mysql> SET optimizer_trace="enabled=on";
    Query OK, 0 rows affected (0.03 sec)
    
    mysql> select * from employee where emp_id = 1 and dept_id = emp_id;
    +--------+----------+-----+---------+---------+------------+--------+----------+----------+-------------------+
    | emp_id | emp_name | sex | dept_id | manager | hire_date  | job_id | salary   | bonus    | email             |
    +--------+----------+-----+---------+---------+------------+--------+----------+----------+-------------------+
    |      1 | 刘备     ||       1 |    NULL | 2000-01-01 |      1 | 30000.00 | 10000.00 | liubei@shuguo.com |
    +--------+----------+-----+---------+---------+------------+--------+----------+----------+-------------------+
    1 row in set (0.00 sec)
    
    mysql> select * from information_schema.optimizer_trace\G
    *************************** 1. row ***************************
                                QUERY: select * from employee where emp_id = 1 and dept_id = emp_id
                                TRACE: {
      "steps": [
        {
          "join_preparation": {
            "select#": 1,
            "steps": [
              {
                "expanded_query": "/* select#1 */ select `employee`.`emp_id` AS `emp_id`,`employee`.`emp_name` AS `emp_name`,`employee`.`sex` AS `sex`,`employee`.`dept_id` AS `dept_id`,`employee`.`manager` AS `manager`,`employee`.`hire_date` AS `hire_date`,`employee`.`job_id` AS `job_id`,`employee`.`salary` AS `salary`,`employee`.`bonus` AS `bonus`,`employee`.`email` AS `email` from `employee` where ((`employee`.`emp_id` = 1) and (`employee`.`dept_id` = `employee`.`emp_id`))"
              }
            ]
          }
        },
        {
          "join_optimization": {
            "select#": 1,
            "steps": [
              {
                "condition_processing": {
                  "condition": "WHERE",
                  "original_condition": "((`employee`.`emp_id` = 1) and (`employee`.`dept_id` = `employee`.`emp_id`))",
                  "steps": [
                    {
                      "transformation": "equality_propagation",
                      "resulting_condition": "(multiple equal(1, `employee`.`emp_id`, `employee`.`dept_id`))"
                    },
                    {
                      "transformation": "constant_propagation",
                      "resulting_condition": "(multiple equal(1, `employee`.`emp_id`, `employee`.`dept_id`))"
                    },
                    {
                      "transformation": "trivial_condition_removal",
                      "resulting_condition": "multiple equal(1, `employee`.`emp_id`, `employee`.`dept_id`)"
                    }
                  ]
                }
              },
    		  ...
            ]
          }
        },
        {
          "join_execution": {
            "select#": 1,
            "steps": [
            ]
          }
        }
      ]
    }
    MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0
              INSUFFICIENT_PRIVILEGES: 0
    1 row in set (0.00 sec)
    

    优化器跟踪输出主要包含了三个部分:

    • join_preparation,准备阶段,返回了字段名扩展之后的 SQL 语句。对于 1=1 这种多余的条件,也会在这个步骤被删除;
    • join_optimization,优化阶段。其中 condition_processing 中包含了各种逻辑转换,经过等值传递(equality_propagation)之后将条件 dept_id = emp_id 转换为了 dept_id = 1。另外 constant_propagation 表示常量传递,trivial_condition_removal 表示无效条件移除
    • join_execution,执行阶段。

    优化器跟踪还可以显示其他基于成本优化的过程,后续我们还会使用该功能。关闭优化器跟踪功能的方式如下:

    SET optimizer_trace="enabled=off";
    

    下表列出了一些逻辑转换的示例:

    原始语句 重写形式 备注
    select *
    from employee
    where emp_id = 1;
    /* select#1 */ select ‘1’ AS `emp_id`,‘刘备’ AS `emp_name`,‘男’ AS `sex`,‘1’ AS `dept_id`,NULL AS `manager`,‘2000-01-01’ AS `hire_date`,‘1’ AS `job_id`,‘30000.00’ AS `salary`,‘10000.00’ AS `bonus`,‘liubei@shuguo.com’ AS `email` from `hrdb`.`employee` where true 通过主键或唯一索引进行等值查找时,在选择执行计划之前就完成了转换,重写为查询常量。
    select *
    from employee
    where emp_id = 0;
    /* select#1 */ select NULL AS `emp_id`,NULL AS `emp_name`,NULL AS `sex`,NULL AS `dept_id`,NULL AS `manager`,NULL AS `hire_date`,NULL AS `job_id`,NULL AS `salary`,NULL AS `bonus`,NULL AS `email` from `hrdb`.`employee` where multiple equal(0, NULL) 通过主键或唯一索引查找不存在的值。
    select emp_name from employee e,
    (select * from department where dept_name =‘研发部’) as d
    where d.dept_id = e.dept_id and e.salary > 10000;
    /* select#1 */ select `hrdb`.`e`.`emp_name` AS `emp_name` from `hrdb`.`employee` `e` join `hrdb`.`department` where ((`hrdb`.`e`.`dept_id` = `hrdb`.`department`.`dept_id`) and (`hrdb`.`e`.`salary` > 10000.00) and (`hrdb`.`department`.`dept_name` = ‘研发部’)) 派生表子查询转换为连接查询

    基于成本的优化

    MySQL 优化器采用基于成本的优化方式,简化的步骤如下:

    1. 为每个操作指定一个成本;
    2. 计算每个可能的执行计划各个步骤的成本总和;
    3. 选择总成本最小的执行计划。

    为了找到最佳执行计划,优化器需要比较不同的查询方案。随着查询中表的数量增加,可能的执行计划会呈现指数级增长;因为每个表都可能使用全表扫描或者不同的索引访问方法,连接查询可能使用任意顺序。对于少量表的连接查询(通常少于 7 到 10 个)可能不会产生问题,但是更多的表可能会导致查询优化的时间比执行时间还要长。

    所以优化器不可能遍历所有的执行方案,一种更灵活的优化方法是允许用户控制优化器在查找最佳查询计划时的遍历程度。一般来说,优化器评估的计划越少,则编译查询所花费的时间就越少;但另一方面,由于优化器忽略了一些计划,因此可能找到的不是最佳计划。

    控制优化程度

    MySQL 提供了两个系统变量,可以用于控制优化器的优化程度:

    • optimizer_prune_level, 基于返回行数的评估忽略某些执行计划,这种启发式的方法可以极大地减少优化时间而且很少丢失最佳计划。因此,该参数的默认设置为 1;如果确认优化器错过了最佳计划,可以将该参数设置为 0,不过这样可能导致优化时间的增加。
    • optimizer_search_depth,优化器查找的深度。如果该参数大于查询中表的数量,可以得到更好的执行计划,但是优化时间更长;如果小于表的数量,可以更快完成优化,但可能获得的不是最优计划。例如,对于 12、13 个或者更多表的连接查询,如果将该参数设置为表的个数,可能需要几小时或者几天时间才能完成优化;如果将该参数修改为 3 或者 4,优化时间可能少于 1 分钟。该参数的默认值为 62;如果不确定是否合适,可以将其设置为 0,让优化器自动决定搜索的深度。

    设置成本常量

    MySQL 优化器计算的成本主要包括 I/O 成本和 CPU 成本,每个步骤的成本由内置的“成本常量”进行估计。另外,这些成本常量可以通过 mysql 系统数据库中的 server_cost 和 engine_cost 两个表进行查询和设置。

    server_cost 中存储的是常规服务器操作的成本估计值:

    select * from mysql.server_cost;
    cost_name                   |cost_value|last_update        |comment|default_value|
    ----------------------------|----------|-------------------|-------|-------------|
    disk_temptable_create_cost  |          |2018-05-17 10:12:12|       |         20.0|
    disk_temptable_row_cost     |          |2018-05-17 10:12:12|       |          0.5|
    key_compare_cost            |          |2018-05-17 10:12:12|       |         0.05|
    memory_temptable_create_cost|          |2018-05-17 10:12:12|       |          1.0|
    memory_temptable_row_cost   |          |2018-05-17 10:12:12|       |          0.1|
    row_evaluate_cost           |          |2018-05-17 10:12:12|       |          0.1|
    

    cost_value 为空表示使用 default_value。其中,

    • disk_temptable_create_cost 和 disk_temptable_row_cost 代表了在基于磁盘的存储引擎(InnoDB 或 MyISAM)中使用内部临时表的评估成本。增加这些值会使得优化器倾向于较少使用内部临时表的查询计划。
    • key_compare_cost 代表了比较记录键的评估成本。增加该值将导致需要比较多个键值的查询计划变得更加昂贵。例如,执行 filesort 排序的查询计划比通过索引避免排序的查询计划相对更加昂贵。
    • memory_temptable_create_cost 和 memory_temptable_row_cost 代表了在 MEMORY 存储引擎中使用内部临时表的评估成本。增加这些值会使得优化器倾向于较少使用内部临时表的查询计划。
    • row_evaluate_cost 代表了计算记录条件的评估成本。增加该值会导致检查许多数据行的查询计划变得更加昂贵。例如,与读取少量数据行的索引范围扫描相比,全表扫描变得相对昂贵。

    engine_cost 中存储的是特定存储引擎相关操作的成本估计值:

    select * from mysql.engine_cost;
    engine_name|device_type|cost_name             |cost_value|last_update        |comment|default_value|
    -----------|-----------|----------------------|----------|-------------------|-------|-------------|
    default    |          0|io_block_read_cost    |          |2018-05-17 10:12:12|       |          1.0|
    default    |          0|memory_block_read_cost|          |2018-05-17 10:12:12|       |         0.25|
    

    engine_name 表示存储引擎,“default”表示所有存储引擎,也可以为不同的存储引擎插入特定的数据。cost_value 为空表示使用 default_value。其中,

    • io_block_read_cost 代表了从磁盘读取索引或数据块的成本。增加该值会使读取许多磁盘块的查询计划变得更加昂贵。例如,与读取较少块的索引范围扫描相比,全表扫描变得相对昂贵。
    • memory_block_read_cost 与 io_block_read_cost 类似,但它表示从数据库缓冲区读取索引或数据块的成本。

    我们来看一个例子,执行以下语句:

    explain format=json
    select *
    from employee
    where dept_id between 4 and 5;
    
    {
      "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "2.75"
        },
        "table": {
          "table_name": "employee",
          "access_type": "ALL",
          "possible_keys": [
            "idx_emp_dept"
          ],
          "rows_examined_per_scan": 25,
          "rows_produced_per_join": 17,
          "filtered": "68.00",
          "cost_info": {
            "read_cost": "1.05",
            "eval_cost": "1.70",
            "prefix_cost": "2.75",
            "data_read_per_join": "9K"
          },
          "used_columns": [
            "emp_id",
            "emp_name",
            "sex",
            "dept_id",
            "manager",
            "hire_date",
            "job_id",
            "salary",
            "bonus",
            "email"
          ],
          "attached_condition": "(`hrdb`.`employee`.`dept_id` between 4 and 5)"
        }
      }
    }
    

    查询计划显示使用了全表扫描(access_type = ALL),而没有选择 idx_emp_dept。通过优化器跟踪可以看到具体原因:

                      "analyzing_range_alternatives": {
                        "range_scan_alternatives": [
                          {
                            "index": "idx_emp_dept",
                            "ranges": [
                              "4 <= dept_id <= 5"
                            ],
                            "index_dives_for_eq_ranges": true,
                            "rowid_ordered": false,
                            "using_mrr": false,
                            "index_only": false,
                            "rows": 17,
                            "cost": 6.21,
                            "chosen": false,
                            "cause": "cost"
                          }
                        ],
                        "analyzing_roworder_intersect": {
                          "usable": false,
                          "cause": "too_few_roworder_scans"
                        }
                      }
    

    使用全表扫描的总成本为 2.75,使用范围扫描的总成本为 6.21。这是因为查询返回了 employee 表中大部分的数据,通过索引范围扫描,然后再回表反而会比直接扫描表更慢。

    接下来我们将数据行比较的成本常量 row_evaluate_cost 从 0.1 改为 1,并且刷新内存中的值:

    update mysql.server_cost 
    set cost_value=1 
    where cost_name='row_evaluate_cost';
    
    flush optimizer_costs;
    

    然后重新连接数据库,再次获取执行计划的结果如下:

    {
      "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "38.51"
        },
        "table": {
          "table_name": "employee",
          "access_type": "range",
          "possible_keys": [
            "idx_emp_dept"
          ],
          "key": "idx_emp_dept",
          "used_key_parts": [
            "dept_id"
          ],
          "key_length": "4",
          "rows_examined_per_scan": 17,
          "rows_produced_per_join": 17,
          "filtered": "100.00",
          "index_condition": "(`hrdb`.`employee`.`dept_id` between 4 and 5)",
          "cost_info": {
            "read_cost": "21.51",
            "eval_cost": "17.00",
            "prefix_cost": "38.51",
            "data_read_per_join": "9K"
          },
          "used_columns": [
            "emp_id",
            "emp_name",
            "sex",
            "dept_id",
            "manager",
            "hire_date",
            "job_id",
            "salary",
            "bonus",
            "email"
          ]
        }
      }
    }
    

    此时,优化器选择的范围扫描(access_type = range)。虽然它的成本增加为 38.51,但是使用全表扫描的代价更高。

    最后,记得将 row_evaluate_cost 的还原成默认设置并重新连接数据库:

    update mysql.server_cost 
    set cost_value= null
    where cost_name='row_evaluate_cost';
    
    flush optimizer_costs;
    

    ⚠️不要轻易修改成本常量,因为这样可能导致许多查询计划变得更糟!在大多数生产情况下,推荐通过添加优化器提示(optimizer hint)控制查询计划的选择。

    数据字典与统计信息

    除了成本常量之外,MySQL 优化器在优化的过程中还会使用数据字典和存储引擎中的统计信息。例如表的数据量、索引、索引的唯一性以及字段是否可空都会影响到执行计划的选择,包括数据的访问方法和表的连接顺序等。

    MySQL 会在日常操作过程中粗略统计表的大小和索引的基数(Cardinality),我们也可以使用 ANALYZE TABLE 语句手动更新表的统计信息和索引的数据分布。

    ANALYZE TABLE tbl_name [, tbl_name] ...;
    

    这些统计信息默认会持久化到数据字典表 mysql.innodb_index_stats 和 mysql.innodb_table_stats 中,也可以通过 INFORMATION_SCHEMA 视图 TABLES、STATISTICS 以及 INNODB_INDEXES 进行查看。

    另外,从 MySQL 8.0 开始增加了直方图统计(histogram statistics),也就是字段值的分布情况。用户同样可以通过ANALYZE TABLE语句生成或者删除字段的直方图:

    ANALYZE TABLE tbl_name
    UPDATE HISTOGRAM ON col_name [, col_name] ...
    [WITH N BUCKETS];
    
    ANALYZE TABLE tbl_name
    DROP HISTOGRAM ON col_name [, col_name] ...;
    

    其中,WITH N BUCKETS 用于指定直方图统计时桶的个数,取值范围从 1 到 1024,默认为 100。

    直方图统计主要用于没有创建索引的字段,当查询使用这些字段与常量进行比较时,MySQL 优化器会使用直方图统计评估过滤之后的行数。例如,以下语句显示了没有直方图统计时的优化器评估:

    explain analyze
    select * 
    from employee
    where salary = 10000;
    -> Filter: (employee.salary = 10000.00)  (cost=2.75 rows=3) (actual time=0.612..0.655 rows=1 loops=1)
        -> Table scan on employee  (cost=2.75 rows=25) (actual time=0.455..0.529 rows=25 loops=1)
    

    由于 salary 字段上既没有索引也没有直方图统计,因此优化器评估返回的行数为 3,但实际返回的行数为 1。

    我们为 salary 字段创建直方图统计:

    analyze table employee update histogram on salary;
    Table        |Op       |Msg_type|Msg_text                                         |
    -------------|---------|--------|-------------------------------------------------|
    hrdb.employee|histogram|status  |Histogram statistics created for column 'salary'.|
    

    然后再次查看执行计划:

    explain analyze
    select * 
    from employee
    where salary = 10000;
    -> Filter: (employee.salary = 10000.00)  (cost=2.75 rows=1) (actual time=0.265..0.291 rows=1 loops=1)
        -> Table scan on employee  (cost=2.75 rows=25) (actual time=0.206..0.258 rows=25 loops=1)
    

    此时,优化器评估的行数和实际返回的行数一致,都是 1。

    MySQL 使用数据字典表 column_statistics 存储字段值分布的直方图统计,用户可以通过查询视图 INFORMATION_SCHEMA.COLUMN_STATISTICS 获得直方图信息:

    select * from information_schema.column_statistics;
    SCHEMA_NAME|TABLE_NAME|COLUMN_NAME|HISTOGRAM                                                                                                                                                                                                                                                      |
    -----------|----------|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
    hrdb       |employee  |salary     |{"buckets": [[4000.00, 0.08], [4100.00, 0.12], [4200.00, 0.16], [4300.00, 0.2], [4700.00, 0.24000000000000002], [4800.00, 0.28], [5800.00, 0.32], [6000.00, 0.4], [6500.00, 0.48000000000000004], [6600.00, 0.52], [6800.00, 0.56], [7000.00, 0.600000000000000|
    

    删除以上直方图统计的命令如下:

    analyze table employee drop histogram on salary;
    

    索引和直方图之间的区别在于:

    • 索引需要随着数据的修改而更新;
    • 直方图通过命令手动更新,不会影响数据更新的性能。但是,直方图统计会随着数据修改变得过时。

    相对于直方图统计,优化器会优先选择索引范围优化评估返回的数据行。因为对于索引字段而言,范围优化可以获得更加准确的评估。

    控制优化行为

    MySQL 提供了一个系统变量 optimizer_switch,用于控制优化器的优化行为。

    select @@optimizer_switch;
    @@optimizer_switch                                                                                                                                                                                                                                             |
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
    index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,
    index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,
    semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,
    condition_fanout_filter=on,derived_merge=on,use_invisible_indexes=off,skip_scan=on,hash_join=on|
    

    它的值由一组标识组成,每个标识的值都可以为 on 或 off,表示启用或者禁用了相应的优化行为。

    该变量支持全局和会话级别的设置,可以在运行时进行更改。

    SET [GLOBAL|SESSION] optimizer_switch='command[,command]...';
    

    其中,command 可以是以下形式:

    • default,将所有优化行为设置为默认值。
    • opt_name=default,将指定优化行为设置为默认值。
    • opt_name=off,禁用指定的优化行为。
    • opt_name=on,启用指定的优化行为。

    我们以索引条件下推(index_condition_pushdown)优化为例,演示修改 optimizer_switch 的效果。首先执行以下语句查看执行计划:

    explain
    select * 
    from employee e
    where e.email like 'zhang%';
    
    id|select_type|table|partitions|type |possible_keys|key         |key_len|ref|rows|filtered|Extra                |
    --|-----------|-----|----------|-----|-------------|------------|-------|---|----|--------|---------------------|
     1|SIMPLE     |e    |          |range|uk_emp_email |uk_emp_email|302    |   |   2|   100.0|Using index condition|
    

    其中,Extra 字段中的“Using index condition”表示使用了索引条件下推。

    然后禁用索引条件下推优化:

    set @@optimizer_switch='index_condition_pushdown=off';
    

    然后再次查看执行计划:

    id|select_type|table|partitions|type |possible_keys|key         |key_len|ref|rows|filtered|Extra      |
    --|-----------|-----|----------|-----|-------------|------------|-------|---|----|--------|-----------|
     1|SIMPLE     |e    |          |range|uk_emp_email |uk_emp_email|302    |   |   2|   100.0|Using where|
    

    Extra 字段变成了“Using where”,意味着需要访问表中的数据然后再应用该条件过滤。如果使用优化器跟踪,可以看到更详细的差异。

    优化器和索引提示

    虽然通过系统变量 optimizer_switch 可以控制优化器的优化策略,但是一旦改变它的值,后续的查询都会受到影响,除非再次进行设置。

    另一种控制优化器策略的方法就是优化器提示(Optimizer Hint)和索引提示(Index Hint),它们只对单个语句有效,而且优先级比 optimizer_switch 更高。

    优化器提示使用 /*+ … */ 注释风格的语法,可以对连接顺序、表访问方式、索引使用方式、子查询、语句执行时间限制、系统变量以及资源组等进行语句级别的设置。

    例如,在没有使用优化器提示的情况下:

    explain
    select * 
    from employee e
    join department d on d.dept_id = e.dept_id
    where e.salary = 10000;
    id|select_type|table|partitions|type  |possible_keys|key    |key_len|ref           |rows|filtered|Extra      |
    --|-----------|-----|----------|------|-------------|-------|-------|--------------|----|--------|-----------|
     1|SIMPLE     |e    |          |ALL   |idx_emp_dept |       |       |              |  25|     4.0|Using where|
     1|SIMPLE     |d    |          |eq_ref|PRIMARY      |PRIMARY|4      |hrdb.e.dept_id|   1|   100.0|           |
    

    优化器选择 employee 作为驱动表,并且使用全表扫描返回 salary = 10000 的数据;然后通过主键查找 department 中的记录。

    然后我们通过优化器提示 join_order 修改两个表的连接顺序:

    explain
    select /*+ join_order(d, e) */ * 
    from employee e
    join department d on d.dept_id = e.dept_id
    where e.salary = 10000;
    id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra                                     |
    --|-----------|-----|----------|----|-------------|---|-------|---|----|--------|------------------------------------------|
     1|SIMPLE     |d    |          |ALL |PRIMARY      |   |       |   |   6|   100.0|                                          |
     1|SIMPLE     |e    |          |ALL |idx_emp_dept |   |       |   |  25|     4.0|Using where; Using join buffer (hash join)|
    

    此时,优化器选择了 department 作为驱动表;同时访问 employee 时选择了全表扫描。我们可以再增加一个索引相关的优化器提示 index:

    explain
    select /*+ join_order(d, e) index(e idx_emp_dept) */ * 
    from employee e
    join department d on d.dept_id = e.dept_id
    where e.salary = 10000;
    id|select_type|table|partitions|type|possible_keys|key         |key_len|ref           |rows|filtered|Extra      |
    --|-----------|-----|----------|----|-------------|------------|-------|--------------|----|--------|-----------|
     1|SIMPLE     |d    |          |ALL |PRIMARY      |            |       |              |   6|   100.0|           |
     1|SIMPLE     |e    |          |ref |idx_emp_dept |idx_emp_dept|4      |hrdb.d.dept_id|   5|    10.0|Using where|
    

    最终,优化器选择了通过索引 idx_emp_dept 查找 employee 中的数据。

    需要注意的是,通过提示禁用某个优化行为可以阻止优化器使用该优化;但是启用某个优化行为不代表优化器一定会使用该优化,它可以选择使用或者不使用。

    ⚠️开发和测试过程可以使用优化器提示和索引提示,但是生产环境中需要小心使用。因为实际数据和环境会随着时间发生变化,而且 MySQL 优化器也会越来越智能,合理的参数配置定时的统计更新通常是更好地选择。

    索引提示为优化器提供了如何选择索引的信息,直接出现在表名之后:

    tbl_name [[AS] alias] 
        USE {INDEX|KEY} [FOR {JOIN|ORDER BY|GROUP BY}] (index_name, ...)
      | {IGNORE|FORCE} {INDEX|KEY} [FOR {JOIN|ORDER BY|GROUP BY}] (index_name, ...)
    

    USE INDEX 提示优化器使用某个索引,IGNORE INDEX 提示优化器忽略某个索引,FORCE INDEX 强制使用某个索引。

    例如,以下语句使用了 USE INDEX 索引提示:

    explain
    select * 
    from employee e use index (idx_emp_job)
    join department d on d.dept_id = e.dept_id
    where e.salary = 10000;
    id|select_type|table|partitions|type  |possible_keys|key    |key_len|ref           |rows|filtered|Extra      |
    --|-----------|-----|----------|------|-------------|-------|-------|--------------|----|--------|-----------|
     1|SIMPLE     |e    |          |ALL   |             |       |       |              |  25|    10.0|Using where|
     1|SIMPLE     |d    |          |eq_ref|PRIMARY      |PRIMARY|4      |hrdb.e.dept_id|   1|   100.0|           |
    

    虽然我们使用了索引提示,但是由于索引 idx_emp_job 和查询完全无关,优化器最终还是没有选择使用该索引。

    以下示例使用了 IGNORE INDEX 索引提示:

    explain
    select * 
    from employee e
    join department d ignore index (PRIMARY)
    on d.dept_id = e.dept_id
    where e.salary = 10000;
    id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra                                     |
    --|-----------|-----|----------|----|-------------|---|-------|---|----|--------|------------------------------------------|
     1|SIMPLE     |e    |          |ALL |idx_emp_dept |   |       |   |  25|    10.0|Using where                               |
     1|SIMPLE     |d    |          |ALL |             |   |       |   |   6|   16.67|Using where; Using join buffer (hash join)|
    

    IGNORE INDEX 使得优化器放弃了 department 的主键查找,最终选择了 hash join 连接两个表。该示例也可以通过优化器提示 no_index 实现:

    explain
    select /*+ no_index(d PRIMARY) */ * 
    from employee e
    join department d
    on d.dept_id = e.dept_id
    where e.salary = 10000;
    

    ⚠️从 MySQL 8.0.20 开始,提供了等价形式的索引级别优化器提示,将来可能会废弃传统形式的索引提示。

    总结

    MySQL 优化器使用基于成本的优化方式,利用数据字典和统计信息选择 SQL 语句的最佳执行方式。同时,MySQL 为我们提供了控制优化器的各种选项,包括控制优化程度、设置成本常量、统计信息收集、启用/禁用优化行为以及使用优化器提示等。

    如果觉得文章对你有用,欢迎订阅我的专栏《MySQL性能优化》

    展开全文
  • SEO站内优化需要做什么工作

    千次阅读 2018-03-01 10:49:22
    SEO优化一直是很多站长非常...有很多站长一直说在SEO,结果到头来还是不知道站内优化主要是做哪些工作?如果你要问站内优化有 哪些?简单的说,站内优化要主要的地方有:三个标签(title、keyword、discretion)、...

      SEO优化一直是很多站长非常重视的一件事情,今年的优化重点主要是在网站内容这一块,也就是站内优化,现在像外链建设,作弊呀在现在的搜索板块几乎消失殆尽了,因此很多站长也把注意力放在站内SEO优化的上面。

    有很多站长一直说在SEO,结果到头来还是不知道站内优化主要是做哪些工作?如果你要问站内优化有 哪些?简单的说,站内优化要主要的地方有:三个标签(title、keyword、discretion)、三个导航(主导航、次导航、位置导航就是面包屑导航)、url(标准化,静态化,绝对地址,还有首选域,301)等。

    这都老站长对新站长说的,他们其实有保留,站内SEO优化有很多的,这个只是大家常做的站内优化,下面小编就全面的给大家讲讲站内SEO优化到底要做哪些工作?


    1、网站标题

    不论是网站主标题(也就是网站名称),还是网站内容页的内容标题,其中最主要的两者都尽可能的出现关键词,就说网站标题,大家都知道在网站标题中添加关键词可以让关键词得到更好的排名,但是站长需要切记的一点是千万不要堆砌关键词。

    总之,标题的优化处理是非常重要的,许多站长把关键词都堆到标题中,以为这样就利于提高排名,其实不然,如果标题中堆砌过多的关键词的话,很容易就让搜索引挚判为优化过度,而网站得到的并非是提高排名而是网站被降权甚至被K。


    2、网站导航

    网站导航是为了让用户可以从首页就知道网站所含括的类型,而且导航也是蜘蛛爬行进入网站内容页面的通道,自然对于导航的优化处理既需要符合也要符合搜索引挚优化。

    一般来说,导航尽量使用文字作链接和树型结构。因为搜索引挚对于使用图片、FLASH、JS代码来作为导航锚文本的网站都不是那么感冒,大家都知道其实这三种都不利于蜘蛛爬行的,尽管搜索引挚可以认识一些简单的图片,但是在文字和图片中,搜索引挚还是喜欢文字多一点。

    所以说,千万不要为了让网站显示花哨些而在导航中使用大量的图片或FLASH,虽然这两者看起来比较有生气,但是别忘了简单的才是最好的这个道理,而且图片和FLASH的加载时间长会影响到网站的打开速度的,建议尽量的不要使用,如果一定要使用的话那么尽量的少用为妙。


    3、网站整体结构设置

    一般网站结构最好就是树状结构,建议链接层数不超过3层,这样用户体验好,而且利于蜘蛛爬行,太深蜘蛛就爬不起来,百度就会让蜘蛛直接跳出网站,那样我们就亏了,收录内容肯定少了很多。

    内容尽可能用文字形式表现,如果非要使用到图片或者Flash也要加个标签,说明文字,但还是建议不要使用主流搜索引擎难于识别的形式。

    总之,合理的网站结构优化是正确表达网站的基本内容及其内容之间的层次关系,使得用户在网站中浏览时可以方便地获取信息,是增加用户体验最直接的一个途径,无论对用户还是对搜索引擎都有着非常重要的意义。


    4、分配权重

    分配权重就涉及到网站架构的设计,应尽量扁平化,首页、栏目页、专题页、内容页,应有一个简单清晰的规划,通过站内的的链接关系合理的分配网站的权重,使重要的页面得到更多的权重,有利于其关键词排名的竞争力。


    5、网站URL优化

    网站URL就是每个网页的网址,一篇文章务必只要一个网址,不良的URL往往增加搜引得擎抓取信息的负担,有的直接把搜引得擎拒之门外,在此,提醒大家一点:冗长的,参变量过多的网址不利于搜引得擎的抓取。

    URL普通遵循原则:简单、简洁原则。

    另外,搜索引擎更倾向于静态地址,用户也对静态地址更有好感,而动态地址则不利于收录,所以作为SEO我们网站上使用静态页面,而且使用静态页面还能提高网页的访问速度,也提高了用户访问的数量,不会因为网站太卡打不开而流失客户。


    6、图片ALT标签优化

    就像前文所讲到的搜索引挚对于图片还不能完全识别,一些图片可以被搜索引挚抓取的原因主要就是ALT标签的作用,那么站长应该怎么来做图片的优化呢?

    (1)、站长搜索引挚抓取的角度,图片必须加上ALT标签。

    (2)、ALT标签中不要堆砌关键词,一些站长为了提高关键词的密度,在ALT标签中恨不得把网站所有的关键词都添加一遍,其实ALT标签主要的作用就是为了告诉搜索引挚图片的大概意思是什么,ALT标签相当于文言文的翻译。

    (3)、站长用户的角度,图片优化处理需要做好三点:一清晰度,清晰度越高越受用户喜爱,就像现在的电视一样高清的观看率往往都比普通的要高得多;二大小适中,大家都知道图片越大,加载的时间越长,自然对用户体验很不利的;三与内容的匹配度,这点大家都懂的。

    相对而言,处理好图片优化细节,其实对于搜索引挚能否抓取图片内容亦或用户体验来说,都有莫大的好处,对于提高网站排名也肯定会有帮助的。


    7、网站锚文本优化

    网站锚文本就是网站中的文字链接,也是网站内容的重要组成部分,他可以清楚的告诉搜索引擎,被链接页面包含什么样的内容,网站的文字导航、栏目中的标题链接、文章中的相关链接和网站的友情链接都属于网站锚文本的范畴。

    无论是对于搜索引擎还是对于用户,锚文本都有着非常重要的意义。

    搜索引擎判断一个页面的主要内容是什么,首先从锚文本开始,网站在某个关键词上的锚文本数量越多,这个关键词的排名往往就越靠前,当然也包括站外锚文本,因此锚文本中的文字应该具有一定的解释意义,能够告诉用户和搜索引擎被链接页面上主要内容是什么,在站内锚文本中布局关键词,也是非常有利于SEO排名的。

    我们在设置站内锚文本时,应该遵循以下原则:

    (1)、锚文本的文字能够解释被链接页面的主要内容。

    (2)、锚文本应该使用简短的词语,而不是一个很长的句子或段落。

    (3)、让你的锚文本显而易见,要和周围的普通文字有所区别。

    (4)、不要链接到对于用户来说毫无价值的垃圾站点。

    另外,文档调用最新文章,推荐文章,热门文章,相关文章,还读文章,读过文章,随机文章,最新评论,这样做的目的是:引导用户浏览;最新文章和评论能够自动更新页面;使链接形式更灵活多样,利于搜索引擎收录。


    8、网站死链要清理

    死链接,简单而言就是给搜索引擎添堵,给用户添堵,所以我们要避免网站出现死链接,死链接的数量也是搜索引擎评价一个网站的权威性的一个参考数据,还会影响网站的排名情况,所以网站管理员要经常的检查下自己网站的链接是否出现死链,平时多看看网站日志,哪里堵了一看就知道了,问题也容易找出。


    9、设置好404页面

    其实设置404页面和清理死链的效果是差不多的,用户在访问我们网站的时候,有时候会出现错误页面,404页面也是给用户做一个引导作用,减少网站的跳出来。

    而且设置一个好的404页面同样能给用户好的体验,也是一个很好的网站内部优化的方法。


    10、文章发布

    网站内容质量不仅仅要高而且要突出网站主题,网站文章是网站的血液,是提高网站权重和用户体现的关键环节之一。

    首先,文章要具备较高的原创性和可读性,尽可能的让专业编辑写出具有行业深度和高度的文章,保证文章的原创性和较强的可读性,用不同的话题和热点构建文章和吸引搜素引擎的访问。

    其次,文章内容紧扣网站主题和页面标题。每个页面标题都应该围绕一些热点长尾词或者提升可以流量的话题进行创作,网站文章内容应该和需要的关键词进行高度匹配,并且应该和网站的主题相关,相关性越强,搜索引擎给予的分值也就越高,该页面在网站的权重乃至网页本身的权重都会得到很大的提升。

    再次,页面内容应该尽量减少样板文字的出现次数。站内样板文章过多,会对其他网页造成影响,增加了网页之间的相似程度,影响了网页权重,大量重复的样板文字是导致降权的罪魁祸首之一。

    最后,网站内容的合理更新,网站的更新频率是吸引蜘蛛来访的关键也是源源不断为网站注入新鲜血液的基础。

    做好以上几个层面,内容的更新我们最好做到持之以恒,因为后期对于提高网站权重是大有裨益的。

    博客点评:

    对于站内优化要反复的去检查,只有在长时间的检查之后就会发现自己的不足,老站长就是从一点一滴做起的,如果不是这样的一点一滴,是不会积累出的经验。

    你想要做好网站优化的话,只需要把注意力放在内容质量和体验度上,以客户为导向,同时注意好细节,就能让网站获得相应的优化效果。

    展开全文
  • 什么是百度快照?百度快照的分析 要想分析百度快照,首先要先明白一个问题?什么是百度快照?下面,台州通盛SEO顾问为大家进行详细分析一下: 如果无法打开某个搜索结果,或者打开速度特别慢,该怎么办?“百度快照...

    什么是百度快照?百度快照的分析


      要想分析百度快照,首先要先明白一个问题?什么是百度快照?下面,台州通盛SEO顾问为大家进行详细分析一下:
     

    百度快照


      如果无法打开某个搜索结果,或者打开速度特别慢,该怎么办?“百度快照”能帮您解决问题。每个被收录的网页,在百度上都存有一个纯文本的备份,称为“百度快照”。百度速度较快,您可以通过“快照”快速浏览页面内容。 不过,百度只保留文本内容,所以,那些图片、音乐等非文本信息,快照页面还是直接从原网页调用。如果您无法连接原网页,那么快照上的图片等非文本内容,会无法显示。


      明白了百度快照,那么就知道为什么要对百度快照进行优化了吧。百度快照一直是很多SEO在进行网站优化工作时主要关注的对象,对它的更新时候和更新速度进行自己的分析,并根据所得的数据对企业网站的下一步优化工作做准备。但是在分析百度快照时常常会遇到一些问题,下面分形科技就为大家举例说明一下、首先,需要明确的一点是:网站快照的更新频率与权重并不存在任何直接的关系,网页的抓取频率和快照的更新频率是完全不同的两个概念。

     

      对百度快照的分析
     

      1、百度快照为什么会更新?
     

      每一个被百度收录的网站,baiduspider都会根据其网站内容更新的频率不断的检查有无新网页产生。一般情况下Baiduspider的抓取频率会和网站产生新内容的速度相符。
     

      每个新抓取的或新检查过的网页,搜索引擎都会根据其重要程度以及其时效性价值,以不同的速度去创建索引,通常所说的快照更新时间指的就是索引时间。如果一个网页只是一般的文字变更或者内容没有时效性的价值,并不一定会被搜索引擎认为有快速更新索引的价值,即便百度蜘蛛重新抓取了该网页内容,其快照也不一定会快速更新,但这并不意味着它不重要或者百度更新的速度很慢。
     

      2、快照时间为什么会倒退?
     

      一个重要网页的快照往往会在搜索引擎数据库中保存有多份网页快照,这些快照的抓取时间并不相同。在一些极特殊情况下,搜索引擎系统可能会选择不同于当前搜索结果中的快照版本,导致出现快照时间倒退的情况。这对网站在搜索引擎中的表现无任何影响,也不代表搜索引擎对该网站做了降权处理。
     

      所以快照的更新与页面中是否出现重要新增内容有直接关联,而与网站本身的“权重”、是否“被K”并无直接关联。所以SEO一定要正确的看待百度快照。

      

    百度快照的分析和SEO优化的6项基础工作

     

    SEO优化网站的6项基础工作


      1、对于百度竞价,完全是谁出的钱多,谁排在上面,所以在选择关键词、竞价的时候一定要看好那些词转化率高。
     

      2、在优化关键词的时候,SEO应尽量采用顶级域名来做站点,这样比较容易优化。
     

      3、做优化的网站一定要使用稳定、速度快的空间,因为百度蜘蛛在抓取时,如果网站的空间,无法访问,蜘蛛就不能抓取到数据。
     

      4、网站没上线之前,一定要先把内容填充饱满。
     

      5、网站上线后,每天定时更新文章、做网站外部链接。
     

      6、把每天的工作,要干些什么,一定要仔细写好,去执行,然后每天按照自己的工作去做就好了。【台州SEO公司


      综上所述,明白了百度快照、也分析了百度快照,又懂得了SEO优化网站的基础工作,那么剩下来就是去实战操作了,理论结合实践永远是正确的,在实践中检验自己的seo理论,不断提升自身的SEO水平。

    提示:如果您觉得本文不错,请点击分享给您的好友!谢谢
    展开全文
  • SEO优化步骤是什么

    千次阅读 2018-08-01 17:35:58
    SEO优化其实是网站优化的一部分,大意就是搜索引擎优化,无论是网站内部优化,还是站外优化,都包含其中,从而提高搜索引擎上的排名,起到直接销售或者企业品牌推广的作用,保障企业通过线上服务获得足够的利润。...

    SEO优化其实是网站优化的一部分,大意就是搜索引擎优化,无论是网站内部优化,还是站外优化,都包含其中,从而提高搜索引擎上的排名,起到直接销售或者企业品牌推广的作用,保障企业通过线上服务获得足够的利润。为了扩展视野,就让我们一起来了解一下SEO优化的步骤是怎样的吧,并不是简单的几个小建议,而是技术和脑力的结合体,需要很大的精力才能够全部了解清楚。学习加群前面461中间860后面887连起来就可以进群学习啦。

    第一、关键词分析

     

    SEO优化的第一步,也是该优化最重要的一步。就是将关键词需要关注的量进行分析、关键词与网站的相关性进行分析、关键词的布置和排名预测等相关知识进行分析,将各个部分联系在一起,不是每一个部分都独立于彼此,而是环环相扣,标题和内容等都与关键词密切相关,进行搜索引擎时也会容易被收录和接纳。

     

    第二、网站架构分析

     

    主要包括剔除网站架构设计中不符合人性化设计的部分、实现目录结构的简洁清晰、网站导航的创意性独特,突出性明显和外部链接的优质广泛等内容,这个分析过程中需要进行市场调研,了解用户的需要和偏好,据此对自家网站进行相关优化处理工作,不仅有利于网站结构的整理,还有利于SEO优化。

     

    第三、网站目录和页面优化

     

    这也是SEO优化的基本操作了,将网站的基本信息进行优化处理,保证用户对于网站能够在浏览之后有一定的了解和熟悉。需要注意的地方是,网站的目录最好有一定的逻辑性,如果有各自的页数,还要保证目录的每一项能够内部链接到每一个小标题;页面的字体大小要合适,不能因为过小而失去一大批视力不好的消费者,也不能因为过大没有多少信息而失去有强迫症或者发散能力不强的用户等。

     

    第四、内容发布和链接布置

     

    SEO优化的重要步骤之一就是内容的定期发布和更新,要合理安排网站内容的更新日程和相关讯息;而对于网站的内部链接和外部链接,都需要保证网页的关键词突出明显,能够被轻易捕捉到重要的信息

    总之,SEO优化不是一件简单的事情,需要脑力劳动的高强度工作,配以高超的技术,加上工作人员的认真程度,才能达到优化的最终效果。

    展开全文
  • 关于Xcode编译性能优化的研究工作总结本文为原创文章,转载注明出处,谢谢!本文链接:关于Xcode编译性能优化的研究工作总结近来(8月1–8月12)结合Xcode的官方文档和网上资料经验对Xcode的一些配置选项进行了编译...
  • MySQL查询优化工作原理解析

    万次阅读 2016-05-28 21:06:31
    手册上MYSQL查询优化器概述;个人对MySQL优化器的理解;分析优化优化过程中的信息;调节MySQL优化器的优化
  • apache配置优化之event工作模式

    千次阅读 2019-04-22 16:47:26
    apache配置优化之worker工作模式 >> prefork和worker模式在非常繁忙的服务器应用下都有些不足。尽管HTTP的Keepalive方式能减少TCP连接数量和网络负载,但是 Keepalive需要和服务进程或者线程绑定,这就导致.....
  • 优化系列一:什么是优化算法

    千次阅读 2019-01-20 21:28:27
    1.优化问题的一般形式 最优化问题的一般数学形式为: minf(x)s.t.x∈Xmin f(x) \\ s.t. \quad x \in Xminf(x)s.t.x∈X 其中,x∈Rnx \in R^nx∈Rn为自变量,f(x)f(x)f(x)为目标函数,x⊂Rnx \subset R^nx⊂Rn为...
  • TDK是什么意思,TDK怎么写?SEO中的TDK分别代表标题,关键词,描述,那么对于TDK如何写能提高网站关键词排名呢?一个好的TDK充分证明该...下面yetaoaiueo跟大家说说SEO中的TDK是什么意思,怎么写利于SEO优化?   ...
  • 本文全面讲解性能优化中的所有知识,献上一份 Android性能优化的详细攻略, 含:优化方向、原因 &amp; 具体优化方案,希望你们会喜欢 文章较长,建议预留较长时间阅读 / 收藏 目录 1. 性能优化...
  • 淄博雷利seo优化团队小雷在此就围绕seo是什么意思?网站seo优化的重要性为话题,来说一下网站建成之后做seo优化的必要性! seo是什么意思?  SEO(Search Engine Optimization),汉译为搜索引擎优化。SEO的主要...
  • 平时我们在学习语文的语法时经常会说到词根这个词,可是由于时间的关系很多人可能都不太记得词根到底是什么意思了,其实在淘宝标题中也有词根的说法,大家知道淘宝标题词根是什么意思吗?  其实词根就是一个关键词...
  • Android中我们经常会用到ListView,然后ListView到底是如何通过ViewHolder去优化的? 1.常见的适配器中利用ViewHolder去优化ListView的代码 @Override public View getView(int position, View convertView, ...
  • 网络优化需要学习什么

    千次阅读 2018-08-29 20:22:56
    1,seo,搜索引擎优化,这是网站优化最核心的东西,另外昆明华信智原再告诉你还有其他需要掌握的辅助技能.2,PS,掌握一定的PS你可以很方便的操作你得网站上的图片3,HTML + CSS,这也是基础的东西,需要基本掌握并...
  • MySQL优化技巧

    万次阅读 多人点赞 2017-09-10 14:14:00
    MySQL优化三大方向① 优化MySQL所在服务器内核(此优化一般由运维人员完成)。② 对MySQL配置参数进行优化(my.cnf)此优化需要进行压力测试来进行参数调整。③ 对SQL语句以及表优化。MySQL参数优化1:MySQL 默认的最大...
  • SQL优化:索引优化

    万次阅读 2017-08-22 08:18:08
    SQL索引 ... 1.1 什么是索引?  SQL索引有两种,聚集索引和非聚集索引,索引主要目的是提高了SQL Server系统的性能,加快数据的查询速度与减少系统的响应时间  下面举两个简单的例子:  图书馆的
  •  什么是ASOASO即APPStoreOptimization,是用于提高APP在应用市场排名的工具,其实也就是移动产品的SEO工作。ASO是为了提高该产品的搜索结果成绩,提升APP的下载量,针对GooglePlay来说,ASO就是优化APP页面。为什么...
  • RabbitMQ的几种工作模式和优化建议

    千次阅读 2020-06-28 16:33:04
    RabbitMQ的几种工作模式和优化建议 1.组件介绍 1.Broker:它提供一种传输服务,它的角色就是维护一条从生产者到消费者的路线,保证数据能按照指定的方式进行传输, 2. Exchange:消息交换机,它指定消息按什么规则,路由...
  • Android性能优化系列之电量优化

    万次阅读 2017-07-07 01:03:24
    电量消耗的计算与统计是一件麻烦而且矛盾的事情,记录电量消耗本身也是一个费电量的事情,随着Android开的性能要求越来越高,电量的优化,也显得格外重要,一个耗电的应用,用户肯定会毫不犹豫的进行卸载,所以本篇...
  • 什么过早的优化是万恶之源?

    千次阅读 2016-01-25 15:35:29
    原文:... “现代计算机科学的鼻祖”Donald Knuth曾说过“过早的优化是万恶之源”,因为:让正确的程序更快,要比让快速的程序正确容易得多。 在
  • 之前安装了Android Studio 1.3,使用了一段时间后,发现已经卡的走不动了,于是从网上搜集了各种优化的方法,改进了相关参数后,发现并没有什么卵用,就干脆的把AS卸载了。PS:那时候还很忙,没时间去学习android开发...
  • java性能优化之字符串优化处理

    千次阅读 2016-07-10 10:18:17
    其实在Java语言中,其设计者也对String做了大量的优化工作,这些也是String对象的特点,它们就是:不变性,常量池优化和String类的final定义。1.1 不变性 String对象的状态在其被创建之后就不在发生变化。为什么说这...
  • 最近工作中,遇到了几个内存优化的问题,1.应用退出后,此应用进程保持了不少内存得不到释放,用工具强制gc也无法释放。2.应用进入某些页面瞬间请求分配内存过大。此两个问题对于有经验的开发者很容易猜测一个是内存...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,113,838
精华内容 445,535
关键字:

优化是什么工作