首页
关于
Search
1
给你10个市场数据调研报告的免费下载网站!以后竞品数据就从这里找!
142 阅读
2
php接口优化 使用curl_multi_init批量请求
132 阅读
3
2024年备考系统架构设计师
102 阅读
4
《从菜鸟到大师之路 ElasticSearch 篇》
102 阅读
5
PHP 文件I/O
89 阅读
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
登录
Search
标签搜索
php函数
php语法
性能优化
安全
错误和异常处理
问题
vue
Composer
Session
缓存
框架
Swoole
api
并发
异步
正则表达式
php-fpm
mysql 索引
开发规范
协程
dafenqi
累计撰写
785
篇文章
累计收到
8
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
785
篇与
的结果
2023-12-25
MySQL索引类型(type)分析
MySQL索引类型(type)分析type索引类型system > const > eq_ref > ref > range > index > all优化级别从左往右递减,没有索引的⼀般为’all’。 推荐优化目标:至少要达到 range 级别, 要求是 ref 级别, 如果可以是 const 最好 ;index比all更优,但是并不明显,性能都很差。Type级别说明1、system级别只有一条数据的系统表;或衍生表只能有一条数据的主查询;这是const类型的特列,实际开发中难以达到(基本不会出现)。2、const级别当使用 主键 或 唯一索引 进行等值查询时实例表结构 CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `age` int(11) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `user_name_IDX` (`name`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8Primary keyexplain select * from `user` u where id=1unique索引explain select * from `user` u where name='zhangsan'3、eq_ref级别当联表查询的关联字段为唯一索引或者主键时实例表结构 CREATE TABLE `user_job` ( `id` int(11) NOT NULL, `userId` int(11) NOT NULL, `job` varchar(255) DEFAULT NULL, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_name` (`name`) USING BTREE, KEY `user_job_userId_IDX` (`userId`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8数据输出结果 explain select uj.id ,u.name ,uj.job from user_job uj left join `user` u on uj.userId =u.id4、ref级别当联表查询的关联字段或者单表查询的筛选字段为普通索引时实例表结构CREATE TABLE `user_job` ( `id` int(11) NOT NULL, `userId` int(11) NOT NULL, `job` varchar(255) DEFAULT NULL, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_name` (`name`) USING BTREE, KEY `user_job_userId_IDX` (`userId`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8输出结果explain select * from user_job uj where name ='xx'5、range级别使用主键或者索引,进行范围查询时常用范围查询 (between , in , > , < , >=),in有时会失效为ALL实例表结构CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `age` int(11) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `user_name_IDX` (`name`) USING BTREE, KEY `user_age_IDX` (`age`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 输出结果explain select * from `user` u where id>1explain select * from `user` u where name in('zhangsan','lisi')explain select * from `user` u where age BETWEEN 10 and 206、index级别遍历索引树,把索引的数据全部查出来explain select id,name from `user` uexplain select age from `user` u7、ALL级别当不使用任何索引和主键时,进行全表扫描explain select * from `user` u
2023年12月25日
23 阅读
0 评论
0 点赞
2023-12-23
API 接口怎样设计才安全?
设计安全的API接口是确保应用程序和数据安全的重要方面之一。下面是一些设计安全的API接口的常见实践:1. 身份验证和授权:使用适当的身份验证机制,如OAuth、JWT或基本身份验证,以确保只有经过身份验证的用户可以访问API。实施授权机制,例如使用令牌或角色/权限来限制用户对资源的访问权限。2. 使用HTTPS:使用安全的传输协议(HTTPS)来加密API通信,以防止数据在传输过程中被窃听或篡改。配置服务器以使用TLS/SSL证书,确保与API的通信是安全的。3. 输入验证和过滤:对所有传入的数据进行验证和过滤,以防止恶意输入或攻击,例如SQL注入、跨站脚本(XSS)等。使用参数校验和输入验证库,如正则表达式或验证框架,来确保输入数据的合法性和安全性。4. 限制访问和频率控制:实施访问控制策略,限制对敏感资源的访问,并防止恶意用户的滥用。实施频率控制机制,限制对API的请求频率,以防止暴力攻击或滥用。5. 错误处理和日志记录:在API中实施适当的错误处理机制,以防止敏感信息泄露,并提供有用的错误消息给开发者和终端用户。记录API请求和响应的日志,以便进行故障排除、安全审计和监控。6. 数据保护和隐私:对于敏感数据,使用适当的加密算法对数据进行加密,以保护数据的机密性。遵循隐私法规和最佳实践,例如数据最小化原则、数据保留期限等,以确保用户数据的安全和隐私。7. 安全审计和漏洞管理:定期进行安全审计和漏洞扫描,以发现和修复潜在的安全漏洞。及时更新和修补API的依赖库和组件,以防止已知的安全漏洞被利用。8. API文档和敏感信息保护:提供清晰、详细和准确的API文档,包括身份验证、授权、请求和响应格式等信息。避免在API响应中返回敏感信息,例如密码、密钥或其他敏感数据。这些实践只是设计安全API接口的一些基本原则,具体的安全需求可能因应用程序的特定情况而有所不同。建议在设计API接口时,根据应用程序的安全需求和最佳实践,采取适当的安全措施来保护API和相关数据的安全性。拓展常见的保证接口数据安全8种方案 API 接口怎样设计才安全?
2023年12月23日
25 阅读
0 评论
0 点赞
2023-12-23
MySQL隐式转换还有这问题?
MySQL隐式转换还有这问题?结论当操作符 左右两边的数据类型 不一致时,会发生隐式转换。当 where 查询操作符 左边为数值类型 时发生了隐式转换,那么对效率影响不大,但还是不推荐这么做。当 where 查询操作符 左边为字符类型 时发生了隐式转换,那么会导致索引失效,造成全表扫描效率极低。字符串转换为数值类型时,非数字开头的字符串会转化为0,以数字开头的字符串会截取从第一个字符到第一个非数字内容为止的值为转化结果。所以,最好的解决方案就是我们一定要养成良好的SQL习惯,where条件的列是什么类型我们就应该传递什么类型,尽量不让MySQL来做隐式转换,就如同上述的情况一,由于隐式转换导致了MySQL不会走索引,导致索引失效触发全表扫描的问题。串会转化为0,以数字开头的字符串会截取从第一个字符到第一个非数字内容为止的值为转化结果。所以,最好的解决方案就是我们一定要养成良好的SQL习惯,where条件的列是什么类型我们就应该传递什么类型,尽量不让MySQL来做隐式转换,就如同上述的情况一,由于隐式转换导致了MySQL不会走索引,导致索引失效触发全表扫描的问题。mysql> desc student; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int | NO | PRI | NULL | auto_increment | | name | varchar(50) | YES | | NULL | | | code | int | YES | | NULL | | | sex | tinyint(1) | NO | | 1 | | +-------+-------------+------+-----+---------+----------------+ 4 rows in set (0.00 sec) mysql> insert into student value(0,3,110001,1); Query OK, 1 row affected (0.00 sec) mysql> select * from student; +----+-----------+------------+-----+ | id | name | code | sex | +----+-----------+------------+-----+ | 1 | 张三丰 | 20181601 | 1 | | 2 | 尔四 | 20181602 | 1 | | 3 | 小红 | 20181603 | 1 | | 4 | 小明 | 20181604 | 1 | | 5 | 小青 | 20181605 | 1 | | 6 | 小明 | 20191302 | 1 | | 7 | 22 | 2138291723 | 1 | | 8 | 李明 | 654368 | 2 | | 10 | 3 | 110001 | 1 | +----+-----------+------------+-----+ 9 rows in set (0.00 sec) mysql> select * from student where name="3"; +----+------+--------+-----+ | id | name | code | sex | +----+------+--------+-----+ | 10 | 3 | 110001 | 1 | +----+------+--------+-----+ 1 row in set (0.00 sec) mysql> select * from student where name=3; +----+------+--------+-----+ | id | name | code | sex | +----+------+--------+-----+ | 10 | 3 | 110001 | 1 | +----+------+--------+-----+ 1 row in set, 7 warnings (0.00 sec)
2023年12月23日
13 阅读
0 评论
0 点赞
2023-12-22
关于PHP不得不说的那几件事
PHP老矣,尚能饭否?(51CTO)语言类型是解释型还是编译型?PHP是一种通用的服务器端脚本语言,经常用于开发动态网页和Web应用程序。它最初设计用于处理网页上的表单数据,但随着时间的推移,它逐渐发展成为一个功能强大的编程语言。PHP被归类为解释型语言。这意味着PHP代码在运行之前不需要显式编译成机器码。相反,PHP脚本以文本形式在服务器上执行,并由PHP解释器逐行解释执行。每当服务器收到对包含PHP代码的网页的请求时,它都会动态地解析和执行代码。解释型语言的一个优点是它的开发过程较为灵活。您可以直接修改PHP代码并立即查看结果,无需额外的编译步骤。这也使得PHP在Web开发中非常受欢迎,因为您可以快速进行迭代和调试。需要注意的是,PHP在执行代码时会进行一些优化,例如将解释的代码缓存起来以提高执行速度。这种缓存机制可以显著降低每次请求的解释和执行开销。总之,PHP是一种解释型语言,它在服务器上动态解析和执行代码,为开发者提供便捷的开发和调试过程。还有哪些解释型语言,哪些是编译型语言以及它们的优点缺点解释型语言和编译型语言是两种常见的编程语言类型。下面是一些常见的解释型语言和编译型语言,以及它们的特点、优点和缺点的详细说明:解释型语言(动态语言):特点:解释型语言的代码在运行时逐行解释执行,而无需显式的编译过程。它们通常具有动态类型系统,在运行时可以更灵活地处理数据类型。例子:Python、Ruby、PHP、JavaScript等。优点:快速开发:解释型语言通常具有简洁的语法和内置的高级功能,可以快速编写代码并迅速迭代开发。跨平台性:由于解释器本身可以在各种操作系统上运行,解释型语言通常具有很好的跨平台兼容性。灵活性:动态类型系统允许在运行时更灵活地处理类型,简化了代码编写和修改的过程。缺点:运行速度:解释型语言的代码在运行时需要逐行解释执行,相对于编译型语言来说,其运行速度可能较慢。可移植性:由于依赖于解释器,解释型语言的可移植性可能较差,需要确保在目标环境中有适当的解释器可用。编译型语言(静态语言):特点:编译型语言的代码在运行之前需要经过显式的编译过程,将源代码编译成可执行的机器码。它们通常具有静态类型系统,在编译时对类型进行检查。例子:C、C++、Java、Go等。优点:高执行效率:编译型语言的代码在运行时已经编译成机器码,因此其执行速度通常更快。严格的类型检查:静态类型系统可以在编译时检查类型错误,提前发现潜在的问题,使得代码更加健壮和可靠。较好的可维护性:编译型语言通常具有较强的模块化和面向对象的特性,使得代码易于组织和维护。缺点:开发速度:编译型语言通常在编写代码和进行调试时需要更多的时间和工作量。学习曲线:相对于解释型语言,编译型语言可能具有更复杂的语法和更严格的规则,需要更多的学习和掌握。需要注意的是,解释型语言和编译型语言之间并没有绝对的界限,有些语言也可以结合两者的特性。例如,Java是一种编译型语言,但它也使用了即时编译器(Just-In-Time, JIT)来优化运行性能。总结来说,解释型语言通常适用于快速开发、动态环境和跨平台需求,而编译型语言则适用于高性能、严格类型检查和可维护性的需求。选择合适的语言取决于具体应用场景和开发需求。php各个版本特性下面是一些PHP版本中的主要特性,以及每个特性的详细说明和示例:1. PHP 5.3 版本特性:命名空间(Namespaces):允许在代码中创建独立的命名空间,避免命名冲突,并提高代码的可组织性和可维护性。<?php namespace MyNamespace; class MyClass { // 类定义 } function myFunction() { // 函数定义 } ?>闭包(Closures):引入匿名函数的概念,可以在运行时创建函数并将其作为值传递、分配给变量、存储在数据结构中或作为回调函数使用。<?php $greeting = function($name) { echo "Hello, $name!"; }; $greeting("John"); // 输出:Hello, John! ?>短数组语法(Short Array Syntax):允许使用方括号快速创建数组。<?php $numbers = [1, 2, 3, 4, 5]; $person = ["name" => "John", "age" => 30]; ?>2. PHP 5.4 版本特性:Traits:引入了Traits的概念,允许多个类之间共享方法的代码块,提供了一种代码复用的机制。<?php trait Loggable { public function log($message) { echo "{$message}\n"; } } class User { use Loggable; // User类的其他代码 } $user = new User(); $user->log("User created."); // 输出:User created. ?>短数组语法中允许使用字符串键名(String Key Array):<?php $person = ["name" => "John", "age" => 30]; echo $person["name"]; // 输出:John ?>内置HTTP服务器(Built-in HTTP Server):可以通过命令行启动PHP内置的轻量级HTTP服务器,方便开发和测试。$ php -S localhost:80003. PHP 5.5 版本特性:生成器(Generators):引入生成器函数,可以逐步生成值,而不是一次性生成所有值,在处理大型数据集时更加高效。<?php function numberGenerator() { for ($i = 0; $i < 10; $i++) { yield $i; } } foreach (numberGenerator() as $number) { echo "$number "; } // 输出:0 1 2 3 4 5 6 7 8 9 ?>4. PHP 5.6 版本特性:可变数量的函数参数(Variadic Function Arguments):允许函数接受不定数量的参数,简化了函数的定义和使用。<?php function sum(...$numbers) { $total = 0; foreach ($numbers as $number) { $total += $number; } return $total; } echo sum(1, 2, 3, 4, 5); // 输出:15 ?>可变数量的参数传递给call_user_func_array()函数:<?php function greetings($name, $age) { echo "Hello, $name! You are $age years old."; } $args = ["John", 30]; call_user_func_array("greetings", $args); // 输出:Hello, John! You are 30 years old. ?>5. PHP 7 版本特性:标量类型声明(Scalar Type Declarations):可以在函数参数和返回类型中声明标量类型(整数、浮点数、布尔值和字符串),提高代码的可靠性和可读性。<?php function multiply(int $a, float $b): float { return $a * $b; } echo multiply(5, 2.5); // 输出:12.5 ?>返回类型声明(Return Type Declarations):可以在函数定义中指定返回值的类型。<?php function getFullName(): string { $firstName = "John"; $lastName = "Doe"; return "$firstName $lastName"; } echo getFullName(); // 输出:John Doe ?>空合并运算符(Null Coalescing Operator):简化了检查和使用可能为null的变量的代码。<?php $username = $_GET["username"] ?? "Guest"; echo "Welcome, $username!"; // 如果$_GET["username"]不存在,输出:Welcome, Guest! ?>6. PHP 8 版本特性:PHP 8是PHP语言的最新版本,带来了一系列强大的特性和改进。以下是PHP 8的一些主要特性和相应的详细说明和示例:JIT(Just-In-Time)编译器:PHP 8引入了JIT编译器,它可以在运行时将PHP代码直接编译成本机机器代码,提高执行性能。JIT编译器可以通过在php.ini文件中进行配置来启用。Union 类型:PHP 8允许在类型声明中指定联合类型,即变量可以是多个类型之一。这提供了更大的灵活性和可读性,比如一个变量可以是整数或浮点数类型。<?php function processNumber(int|float $number) { // 对整数和浮点数执行处理逻辑 } processNumber(10); // 正确 processNumber(3.14); // 正确 processNumber("abc"); // 错误,不是允许的类型 ?>命名参数:PHP 8引入了命名参数,允许在函数调用时通过名称指定参数值,而不是按照参数顺序传递。这样可以提高函数调用的可读性和可维护性。<?php function greet($name, $age) { echo "Hello, $name! You are $age years old."; } greet(age: 30, name: "John"); // 输出:Hello, John! You are 30 years old. ?>Match 表达式:PHP 8中引入了Match表达式,它提供了在多个条件中进行严格值匹配的一种替代方式。<?php $value = 2; $result = match($value) { 1 => "One", 2 => "Two", 3 => "Three", default => "Other" }; echo $result; // 输出:Two ?>nullsafe 运算符:PHP 8中添加了nullsafe运算符(?->),它允许在链式调用中对可能为null的对象进行安全访问,避免了繁琐的条件检查。<?php class User { public function getName() { return "John"; } } class Order { public function getUser() { return null; // 设置为null以模拟对象不存在 } } $order = new Order(); $name = $order->getUser()?->getName(); echo $name; // 输出:null,而不会引发错误 ?>松散类型检查:在PHP 8中,松散类型检查被弃用,使得严格类型检查成为默认行为。这提高了代码的可靠性和一致性,但也需要开发者更加注意类型的正确使用。<?php declare(strict_types=1); // 启用严格类型检查 function sum(int $a, int $b): int { return $a + $b; } echo sum(5, 2); // 输出:7 echo sum(5.5, 2.5); // 错误,参数类型不匹配 ?>上述只是一些PHP版本中引入的主要特性的例子,每个版本还可能包含其他特性和改进。如果您需要更详细的特性列表和使用指南,建议查阅PHP官方文档。官方文档提供了每个版本的详细特性介绍,包括语法示例、用法说明以及与之前版本的兼容性考虑。它是学习和了解各个PHP版本特性的重要资源。
2023年12月22日
15 阅读
0 评论
0 点赞
2023-12-19
实践中如何优化MySQL(精)
实践中如何优化MySQL(精)在开始介绍如何优化sql前,先附上mysql内部逻辑图让大家有所了解(1)连接器:主要负责跟客户端建立连接、获取权限、维持和管理连接(2)查询缓存:优先在缓存中进行查询,如果查到了则直接返回,如果缓存中查询不到,在去数据库中查询。MySQL缓存是默认关闭的,也就是说不推荐使用缓存,并且在MySQL8.0 版本已经将查询缓存的整块功能删掉了。这主要是它的使用场景限制造成的:先说下缓存中数据存储格式:key(sql语句)- value(数据值),所以如果SQL语句(key)只要存在一点不同之处就会直接进行数据库查询了;由于表中的数据不是一成不变的,大多数是经常变化的,而当数据库中的数据变化了,那么相应的与此表相关的缓存数据就需要移除掉;(3)解析器/分析器:分析器的工作主要是对要执行的SQL语句进行词法解析、语法解析,最终得到抽象语法树,然后再使用预处理器对抽象语法树进行语义校验,判断抽象语法树中的表是否存在,如果存在的话,在接着判断select投影列字段是否在表中存在等。(4)优化器:主要将SQL经过词法解析、语法解析后得到的语法树,通过数据字典和统计信息的内容,再经过一系列运算 ,最终得出一个执行计划,包括选择使用哪个索引在分析是否走索引查询时,是通过进行动态数据采样统计分析出来;只要是统计分析出来的,那就可能会存在分析错误的情况,所以在SQL执行不走索引时,也要考虑到这方面的因素(5)执行器:根据一系列的执行计划去调用存储引擎提供的API接口去调用操作数据,完成SQL的执行。一、SQL语句及索引的优化SQL语句的优化1. 尽量避免使用子查询例:SELECT * FROM t1 WHERE id (SELECT id FROM t2 WHERE name = 'chackca');其子查询在Mysql5.5版本里,内部执行计划是这样:先查外表再匹配内表,而不是先查内表t2,当外表的数据很大时,查询速度会非常慢。在MariaDB10/Mysql5.6版本里,采用join关联方式对其进行了优化,这条SQL语句会自动转换为:SELECT t1.* FROM t1 JOIN t2 on t1.id = t2.id但请注意的是:优化只针对SELECT有效,对UPDATE/DELETE子查询无效,固生产环境应避免使用子查询由于MySQL的优化器对于子查询的处理能力比较弱,所以不建议使用子查询,可以改写成Inner Join,之所以 join 连接效率更高,是因为 MySQL不需要在内存中创建临时表2. 用IN来替换OR低效查询:SELECT * FROM t WHERE id = 10 OR id = 20 OR id = 30;高效查询:SELECT * FROM t WHERE id IN (10,20,30);另外,MySQL对于IN做了相应的优化,即将IN中的常量全部存储在一个数组里面,而且这个数组是排好序的。但是如果数值较多,产生的消耗也是比较大的。再例如:select id from table_name where num in(1,2,3) 对于连续的数值,能用 between 就不要用 in 了;再或者使用连接来替换。3. 读取适当的记录LIMIT M,N,而不要读多余的记录select id,name from t limit 866613, 20使用上述sql语句做分页的时候,可能有人会发现,随着表数据量的增加,直接使用limit分页查询会越来越慢。对于 limit m, n 的分页查询,越往后面翻页(即m越大的情况下)SQL的耗时会越来越长,对于这种应该先取出主键id,然后通过主键id跟原表进行Join关联查询。因为MySQL 并不是跳过 offset 行,而是取 offset+N 行,然后放弃前 offset 行,返回 N 行,那当 offset 特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行 SQL 改写。优化的方法如下:使用索引覆盖+子查询优化:因为我们有主键 id,并且在上面建了索引,所以可以先在索引树中找到开始位置的 id 值,再根据找到的 id 值查询行数据。sql可以采用如下的写法:select id,name from table\_name where id > (select id from table\_name order by id limit 866612, 1)起始位置重定义(效率最高,但是要记住ID值):可以取前一页的最大行数的id(将上次遍历到的最末尾的数据ID传给数据库,然后直接定位到该ID处,再往后面遍历数据),然后根据这个最大的id来限制下一页的起点。比如此列中,上一页最大的id是866612。sql可以采用如下的写法:select id,name from table_name where id > 866612 limit 20降级策略(分页场景):配置 limit 的偏移量和获取数一个最大值,超过这个最大值,就返回空数据(4xx错误)。通常在查询时,超过我们配置的这个limit值可以认为用户已经不是在分页了,而是在刷数据了,如果确认要找数据,应该输入合适条件来缩小范围,而不是一页一页分页。4. 禁止不必要的Order By排序如果我们对结果没有排序的要求,就尽量少用排序;如果排序字段没有用到索引,也尽量少用排序;另外,分组统计查询时可以禁止其默认排序SELECT goods\_id,count(*) FROM t GROUP BY goods\_id;默认情况下,Mysql会对所有的GROUP BT col1,col2…的字段进行排序,也就是说上述会对 goods\_id进行排序,如果想要避免排序结果的消耗,可以指定ORDER BY NULL禁止排序:SELECT goods\_id,count(*) FROM t GROUP BY goods_id ORDER BY NULL5. 总和查询可以禁止排重用union allunion和union all的差异主要是前者需要将结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的CPU运算,加大资源消耗及延迟。当然,union all的前提条件是两个结果集没有重复数据。所以一般是我们明确知道不会出现重复数据的时候才建议使用 union all 提高速度。6. 避免随机取记录SELECT * FROM t1 WHERE 1 = 1 ORDER BY RAND() LIMIT 4;SELECT FROM t1 WHERE id >= CEIL(RAND()1000) LIMIT 4;以上两个语句都无法用到索引7. 将多次插入换成批量Insert插入INSERT INTO t(id, name) VALUES(1, 'aaa');INSERT INTO t(id, name) VALUES(2, 'bbb');INSERT INTO t(id, name) VALUES(3, 'ccc');—>INSERT INTO t(id, name) VALUES(1, 'aaa'),(2, 'bbb'),(3, 'ccc');8. 只返回必要的列,用具体的字段列表代替 select * 语句SELECT * 会增加很多不必要的消耗(cpu、io、内存、网络带宽);增加了使用覆盖索引的可能性;当表结构发生改变时,前者也需要经常更新。所以要求直接在select后面接上字段名。MySQL数据库是按照行的方式存储,而数据存取操作都是以一个页大小进行IO操作的,每个IO单元中存储了多行,每行都是存储了该行的所有字段。所以无论取一个字段还是多个字段,实际上数据库在表中需要访问的数据量其实是一样的。但是如果查询的字段都在索引中,也就是覆盖索引,那么可以直接从索引中获取对应的内容直接返回,不需要进行回表,减少IO操作。除此之外,当存在 order by 操作的时候,select 子句中的字段多少会在很大程度上影响到我们的排序效率。9. 区分in和existsselect * from 表A where id in (select id from 表B)上面的语句相当于:select from 表A where exists(select from 表B where 表B.id=表A.id)区分in和exists主要是造成了驱动顺序的改变(这是性能变化的关键),如果是exists,那么以外层表为驱动表,先被访问,如果是IN,那么先执行子查询。所以IN适合于外表大而内表小的情况;EXISTS适合于外表小而内表大的情况。另外,in查询在某些情况下有可能会查询返回错误的结果,因此,通常是建议在确定且有限的集合时,可以使用in。如 IN (0,1,2)。扩展链接10. 优化Group By语句如果对group by语句的结果没有排序要求,要在语句后面加 order by null(group 默认会排序);尽量让group by过程用上表的索引,确认方法是explain结果里没有Using temporary 和 Using filesort;如果group by需要统计的数据量不大,尽量只使用内存临时表;也可以通过适当调大tmp\_table\_size参数,来避免用到磁盘临时表;如果数据量实在太大,使用SQL\_BIG\_RESULT这个提示,来告诉优化器直接使用排序算法(直接用磁盘临时表)得到group by的结果。使用where子句替换Having子句:避免使用having子句,having只会在检索出所有记录之后才会对结果集进行过滤,这个处理需要排序分组,如果能通过where子句提前过滤查询的数目,就可以减少这方面的开销。低效: SELECT JOB, AVG(SAL) FROM EMP GROUP by JOB HAVING JOB = ‘PRESIDENT’ OR JOB = ‘MANAGER’高效: SELECT JOB, AVG(SAL) FROM EMP WHERE JOB = ‘PRESIDENT’ OR JOB = ‘MANAGER’ GROUP by JOB11. 尽量使用数字型字段若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能。引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。12. 优化Join语句当我们执行两个表的Join的时候,就会有一个比较的过程,逐条比较两个表的语句是比较慢的,因此可以把两个表中数据依次读进一个内存块中,在Mysql中执行:show variables like ‘join\_buffer\_size’,可以看到join在内存中的缓存池大小,其大小将会影响join语句的性能。在执行join的时候,数据库会选择一个表把他要返回以及需要进行和其他表进行比较的数据放进join_buffer。什么是驱动表,什么是被驱动表,这两个概念在查询中有时容易让人搞混,有下面几种情况,大家需要了解。当连接查询没有where条件时left join 前面的表是驱动表,后面的表是被驱动表right join 后面的表是驱动表,前面的表是被驱动表inner join / join 会自动选择表数据比较少的作为驱动表straight_join(≈join) 直接选择左边的表作为驱动表(语义上与join类似,但去除了join自动选择小表作为驱动表的特性)当连接查询有where条件时,带where条件的表是驱动表,否则是被驱动表假设有表如右边: t1与t2表完全一样,a字段有索引,b无索引,t1有100条数据,t2有1000条数据若被驱动表有索引,那么其执行算法为:Index Nested-Loop Join(NLJ),示例如下:1.执行语句:select * from t1 straight_join t2 on (t1.a=t2.a);由于被驱动表t2.a是有索引的,其执行逻辑如下:从表t1中读入一行数据 R;从数据行R中,取出a字段到表t2里去查找;取出表t2中满足条件的行,跟R组成一行,作为结果集的一部分;重复执行步骤1到3,直到表t1的末尾循环结束。如果一条join语句的Extra字段什么都没写的话,就表示使用的是NLJ算法若被驱动表无索引,那么其执行算法为:Block Nested-Loop Join(BLJ)(Block 块,每次都会取一块数据到内存以减少I/O的开销),示例如下:2.执行语句:select * from t1 straight_join t2 on (t1.a=t2.b);由于被驱动表t2.b是没有索引的,其执行逻辑如下:把驱动表t1的数据读入线程内存join_buffer(无序数组)中,由于我们这个语句中写的是select *,因此是把整个表t1放入了内存;顺序遍历表t2,把表t2中的每一行取出来,跟join_buffer中的数据做对比,满足join条件的,作为结果集的一部分返回。3.另外还有一种算法为Simple Nested-Loop Join(SLJ),其逻辑为:顺序取出驱动表中的每一行数据,到被驱动表去做全表扫描匹配,匹配成功则作为结果集的一部分返回。另外,Innodb会为每个数据表分配一个存储在磁盘的 表名.ibd 文件,若关联的表过多,将会导致查询的时候磁盘的磁头移动次数过多,从而影响性能所以实践中,尽可能减少Join语句中的NestedLoop的循环次数:“永远用小结果集驱动大的结果集”用小结果集驱动大结果集,将筛选结果小的表(在决定哪个表做驱动表的时候,应该是两个表按照各自的条件过滤,过滤完成之后,计算参与join的各个字段的总数据量,数据量小的那个表,就是“小表”)首先连接,再去连接结果集比较大的表,尽量减少join语句中的Nested Loop的循环总次数优先优化Nested Loop的内层循环(也就是最外层的Join连接),因为内层循环是循环中执行次数最多的,每次循环提升很小的性能都能在整个循环中提升很大的性能;对被驱动表的join字段上建立索引;当被驱动表的join字段上无法建立索引的时候,设置足够的Join Buffer Size。尽量用inner join(因为其会自动选择小表去驱动大表).避免 LEFT JOIN (一般我们使用Left Join的场景是大表驱动小表)和NULL,那么如何优化Left Join呢?1、条件中尽量能够过滤一些行将驱动表变得小一点,用小表去驱动大表2、右表的条件列一定要加上索引(主键、唯一索引、前缀索引等),最好能够使type达到range及以上(ref,eq_ref,const,system)适当地在表里面添加冗余信息来减少join的次数使用更快的固态硬盘性能优化,left join 是由左边决定的,左边一定都有,所以右边是我们的关键点,建立索引要建在右边。当然如果索引是在左边的,我们可以考虑使用右连接,如下select * from atable left join btable on atable.aid=btable.bid;//最好在bid上建索引Tips:Join左连接在右边建立索引;组合索引则尽量将数据量大的放在左边,在左边建立索引索引的优化/如何避免索引失效1.最佳左前缀法则如果索引了多列,要遵守最左前缀法则,指的是查询从索引的最左前列开始并且不跳过索引中的列。Mysql查询优化器会对查询的字段进行改进,判断查询的字段以哪种形式组合能使得查询更快,所有比如创建的是(a,b)索引,查询的是(b,a),查询优化器会修改成(a,b)后使用索引查询。2.不在索引列上做任何操作计算:对索引进行表达式计算会导致索引失效,如 where id + 1 = 10,可以转换成 where id = 10 -1,这样就可以走索引函数:select * from t_user where length(name)=6; 此语句对字段使用到了函数,会导致索引失效从 MySQL 8.0 开始,索引特性增加了函数索引,即可以针对函数计算后的值建立一个索引,也就是说该索引的值是函数计算后的值,所以就可以通过扫描索引来查询数据。alter table t\_user add key idx\_name_length ((length(name)));(自动/手动)类型转换(字符串类型必须带''引号才能使索引生效)字段是varchar,用整型进行查询时,无法走索引,如select * from user where phone = 13030303030;Mysql 在执行上述语句时,会把字段转换为数字再进行比较,所以上面那条语句就相当于:select * from user where CAST(phone AS signed int) = 13030303030;CAST 函数是作用在了 phone 字段,而 phone 字段是索引,也就是对索引使用了函数!所以索引失效字段是int,用string进行查询时,mysql会自动转化,可以走索引,如:select * from user where id = '1';MySQL 在遇到字符串和数字比较的时候,会自动把字符串转为数字,然后再进行比较。以上这条语句相当于:select * from user where id = CAST(“1” AS signed int),索引字段并没有用任何函数,CAST 函数是用在了输入参数,因此是可以走索引扫描的。3.存储引擎不能使用索引中范围条件右边的列。如这样的sql: select * from user where username='123' and age>20 and phone='1390012345',其中username, age, phone都有索引,只有username和age会生效,phone的索引没有用到。4.尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致))如select age from user,减少select *5.mysql在使用负向查询条件(!=、<>、not in、not exists、not like)的时候无法使用索引会导致全表扫描。你可以想象一下,对于一棵B+树,根节点是40,如果你的条件是等于20,就去左面查,你的条件等于50,就去右面查,但是你的条件是不等于66,索引应该咋办?还不是遍历一遍才知道。6.is null, is not null 也无法使用索引,在实际中尽量不要使用null(避免在 where 子句中对字段进行 null 值判断) 不过在mysql的高版本已经做了优化,允许使用索引对于null的判断会导致引擎放弃使用索引而进行全表扫描。7.like 以通配符开头(%abc..)时,mysql索引失效会变成全表扫描的操作。所以最好用右边like ‘abc%’。如果两边都要用,可以用select username from user where username like '%abc%',其中username是必须是索引列,才可让索引生效假如index(a,b,c), where a=3 and b like ‘abc%’ and c=4,a能用,b能用,c不能用,类似于不能使用范围条件右边的列的索引对于一棵B+树索引来讲,如果根节点是字符def,假如查询条件的通配符在后面,例如abc%,则其知道应该搜索左子树,假如传入为efg%,则应该搜索右子树,如果通配符在前面%abc,则数据库不知道应该走哪一面,就都扫描一遍了。8.少用or,在 WHERE 子句中,如果在 OR 前的条件列是索引列,而在 OR 后的条件列不是索引列,那么索引会失效。select * from t_user where id = 1 or age = 18; // id有索引,name没有,此时没法走索引因为 OR 的含义就是两个只要满足一个即可,因此只有一个条件列是索引列是没有意义的,只要有条件列不是索引列,就会进行全表扫描。必须要or前后的字段都有索引,查询才能使用上索引(分别使用,最后合并结果type = index_merge)9.在组合/联合索引中,将有区分度的索引放在前面如果没有区分度,例如用性别,相当于把整个大表分成两部分,查找数据还是需要遍历半个表才能找到,使得索引失去了意义。10.使用前缀索引短索引不仅可以提高查询性能而且可以节省磁盘空间和I/O操作,减少索引文件的维护开销,但缺点是不能用于 ORDER BY 和 GROUP BY 操作,也不能用于覆盖索引。比如有一个varchar(255)的列,如果该列在前10个或20个字符内,可以做到既使前缀索引的区分度接近全列索引,那么就不要对整个列进行索引。为了减少key_len,可以考虑创建前缀索引,即指定一个前缀长度,可以使用count(distinct leftIndex(列名, 索引长度))/count(*) 来计算前缀索引的区分度。11.SQL 性能优化 explain 中的 type:至少要达到 range 级别,要求是 ref 级别,如果可以是 consts 最好。consts:单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。ref:使用普通的索引range:对索引进行范围检索。当 type=index 时,索引物理文件全扫,速度非常慢。二、数据库表结构的优化:使得数据库结构符合三大范式与BCNF三、系统配置的优化四、硬件的优化参考链接:https://www.zhihu.com/question/36996520http://liucw.cn/2018/01/07/mysql/%E7%B4%A2%E5%BC%95%E4%BC%98%E5%8C%96%E5%88%86%E6%9E%90/https://mp.weixin.qq.com/s/7zBJOrlljXIhpuzV69afIg
2023年12月19日
14 阅读
0 评论
0 点赞
1
...
47
48
49
...
157