一、优化语句查询
test表中数据有500w,字段有id/t_id/type_id/plat_id,语句为select max(t_id) from test where type_id=1 and plat_id=1
考察mysql语句优化,这里主要是优化max函数,max函数会导致全表扫描,效率会很低,可以使用order by加limit进行优化
sql
select t_id from test where type_id=1 and plat_id=1 order by t_id desc limit 1;
还可以使用加索引进一步优化速度,给t_id加索引,还有(type_id/plat_id)联合索引。
二、写条语句从user 表随机调取 1 条数据?
select * from user order by rand() limit 1;
使用 RAND() 函数对结果集进行随机排序。
三、如何排查和优化查询比较慢的sql语句?
-
使用MySQL 的慢查询日志
-
通过explain 可以查看一条SQL使用哪些索引和有什么使用临时表
关注以下字段:
type:访问类型,如 ALL、index、range 等。
key:使用的索引名称。
rows:估计的行数。
Extra:其他信息,如是否使用了临时表、文件排序等。
-
优化查询语句本身和添加索引
- 仅选择需要的字段,避免使用 SELECT *。
- 确保 WHERE 条件中使用了索引列。
- 避免在索引列上使用函数或运算符,这会阻止索引的使用。
- 根据查询的 WHERE 条件和连接条件添加索引。
- 过多或不必要的索引会增加写操作的开销,影响性能。
-
对于不经常变化且查询频繁的数据,可以考虑使用缓存,如 Memcached、Redis 等。
四、mysql数据库索引有哪些?什么情况下不适合建立索引?
- 主键索引(Primary Key)
主键索引是唯一标识每条记录的索引,确保表中每行数据都有唯一的标识。
一个表只能有一个主键索引,通常是在主键字段上创建的。 - 唯一索引(Unique Index)
唯一索引确保索引列中的所有值都是唯一的,但允许存在空值(NULL)。
一个表可以有多个唯一索引,可以用来确保列或组合列的唯一性。 - 普通索引(Normal Index)
普通索引是最基本的索引类型,用于加快对列的查询速度。
可以对表中的任意列创建普通索引。 - 全文索引(Full-Text Index)
全文索引用于在文本数据中进行全文搜索,例如文章内容或文档。
可以对 CHAR、VARCHAR 或 TEXT 类型的列创建全文索引。 - 组合索引(Composite Index)
组合索引是包含多个列的索引,用于加快联合条件的查询。
查询时可以利用索引覆盖多个查询条件。 - 空间索引(Spatial Index)
空间索引用于优化空间数据类型的查询,例如地理位置信息。
可以用于 GEOMETRY、POINT、LINESTRING 等空间数据类型的列。
对于经常用作 WHERE 子句中的查询条件、ORDER BY 进行排序、JOIN 操作中连接的列,通过索引可以加快连接操作的速度。
不适合建立索引的情况:
-
低基数的列:基数(Cardinality)指的是列中不同值的数量。如果列中的值几乎全部相同,建立索引的效果会很小。
-
频繁更新的列:对于频繁更新的列(特别是使用 UPDATE 和 DELETE 操作的列),索引可能会增加维护成本,并且在插入新记录时可能会影响性能。
-
小表:对于行数很少的表,查询速度本身已经很快,额外的索引可能不会带来显著的性能提升,反而增加了存储和维护成本。
-
不会用到的列:如果某列很少用作查询条件,或者几乎不会出现在 WHERE 子句中,建立索引可能没有意义。
-
文本/图像类型的列:对于 TEXT、BLOB 等大字段类型,通常不适合建立索引,可以考虑使用全文索引或者其他技术来优化查询。
五、缓存穿透、缓存雪崩、缓存击穿的区别以及对应的解决方案?
-
缓存穿透(Cache Penetration)
问题描述:
缓存穿透指的是恶意或非法访问请求查询一个不存在的缓存数据,导致该查询请求绕过缓存直接访问数据库,从而引起数据库的压力增大。
解决方案:
- 缓存空对象(Cache Null Object):对于不存在的数据,也将其缓存起来,设置一个较短的过期时间,防止恶意请求多次访问。
-
缓存雪崩(Cache Avalanche)
问题描述:
缓存雪崩指的是缓存中大量 的缓存数据同时过期失效,导致大量的请求直接访问数据库,从而造成数据库压力剧增,甚至引发系统崩溃。
解决方案:
- 缓存失效时间随机化:设置缓存的失效时间随机分布,避免大量缓存同时过期。
- 分布式锁:在缓存失效时,使用分布式锁控制同时只有一个请求更新缓存,避免缓存失效时大量请求同时更新。
- 热点数据永不过期:对于重要的热点数据,设置永不过期,保证即使其他数据失效也不影响重要数据的访问。
-
缓存击穿(Cache Miss)
问题描述:
缓存击穿是指某个热点数据过期或被删除,在数据未来得及被缓存之前,大量请求直接打到数据库上,引起数据库宕机
解决方案:
- 设置热点数据永不过期:对于热点数据,采用永不过期的方式,确保即使缓存失效也能保持访问的稳定性。
- 互斥锁(Mutex Lock):在缓存失效时,使用互斥锁控制只有一个请求能够更新缓存,其他请求等待更新完成后再获取数据。
- 预先加载(Preloading):提前加载热点数据到缓存中,确保即使缓存失效时也能快速从缓存中获取数据。
六、安全对一套程序来说至关重要,请说说在开发中应该注意哪些安全机制?
使用验证码防止注册机灌水
使用预处理,绑定参数,参数过滤转义,防止sql注入
使用token防止远程提交,使用token验证登录状态
七、Innodb下创建表,表中不创建主键索引,创建一般索引后,查询逻辑是怎样
- 隐式主键的创建
如果你在创建表时没有定义主键索引,InnoDB会自动创建一个6字节的ROWID作为隐式主键。这是为了保证每一行有一个唯一标识符。 - 查询逻辑
当你对这个表执行查询时,查询逻辑会根据查询条件来决定使用什么索引。
如果你的查询条件包含了索引列(例如name列),InnoDB会使用一般索引来加速查询。查询流程如下:
查找索引:首先,InnoDB会在idx_name索引中查找符合条件的索引项。
获取ROWID:通过索引项找到对应的ROWID(隐式主键)。
查找数据:使用ROWID在聚簇索引(B+树)中找到实际的数据行。
八、有两个文件,大小都超过了 1G,一行一条数据,每行数据不超过 500 字节,两文件中有一部分内容是完全相同的,请写代码找到相同的行,并写到新文件中。PHP 最大允许内存为 255M
解题思路:由于文件较大,需要注意内存的使用,可以将第一个文件逐行读取转换为MD5值,存入数组。第二个文件也逐行读取转换为MD5,并判断每个MD5是否存在于刚才的数组中。
九、请用 SHELL 统计 5 分钟内,nginx 日志里访问最多的 URL 地址,对应的 IP 是哪些?
powershell
#!/bin/bash
# 设置时间范围
start_time=$(date -d "5 minutes ago" "+%d/%b/%Y:%H:%M:%S")
end_time=$(date "+%d/%b/%Y:%H:%M:%S")
# 统计访问最多的URL地址和对应的IP地址
awk -v start_time="$start_time" -v end_time="$end_time" '$4 > "["start_time && $4 < "["end_time {print $1,$7}' access.log | sort | uniq -c | sort -rn | head -10
start_time 和 end_time 分别表示统计的时间范围,这里设置为5分钟前至当前时间
awk 命令用于从日志文件中提取时间、IP地址和URL地址。其中,4表示日志中的时间字段,4表示日志中的时间字段,4表示日志中的时间字段,1 表示日志中的IP地址字段,$7 表示日志中的URL地址字段。
sort 命令用于将提取出来的IP地址和URL地址进行排序
uniq -c 命令用于统计每个IP地址和URL地址的出现次数
sort -rn 命令用于将统计结果按照出现次数从大到小排序
head -10 命令用于只显示出现次数最多的前10个IP地址和URL地址
十、写一段 shell 脚本实现备份 mysql 指定库(如 test) 到指定文件夹并打包,并删除 30 天前的备份,然后将新的备份推送到远端服务器,完成后送邮件通知
powershell
#!/bin/bash
# 备份文件名
BACKUP_NAME="test_$(date +%Y%m%d_%H%M%S).sql"
# 备份目录
BACKUP_DIR="/path/to/backups"
# 本地备份文件路径
BACKUP_FILE="$BACKUP_DIR/$BACKUP_NAME"
# 远端服务器信息
REMOTE_USER="user"
REMOTE_HOST="remote_host"
REMOTE_DIR="/path/to/remote/dir"
# 邮件信息
MAIL_TO="user@example.com"
MAIL_SUBJECT="MySQL Backup Report"
MAIL_BODY="MySQL backup completed successfully."
# 备份 MySQL 数据库
mysqldump -u root -pPASSWORD test > "$BACKUP_FILE"
# 压缩备份文件
tar -czvf "$BACKUP_FILE.tar.gz" "$BACKUP_FILE"
# 删除 30 天前的备份文件
find "$BACKUP_DIR" -type f -name "*.tar.gz" -mtime +30 -delete
# 推送备份文件到远端服务器
scp "$BACKUP_FILE.tar.gz" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR"
# 发送邮件通知
echo "$MAIL_BODY" | mail -s "$MAIL_SUBJECT" "$MAIL_TO"
十一、有 10 亿条订单数据,属于 1000 个司机的,请取出订单量前 20 的司机
sql
SELECT driver_id,COUNT(*) as count FROM order
GROUP BY driver_id
ORDER BY count desc
limit 20
十二、如何以最少流量消耗,获取一个远程资源(假设1G)的最后10个字节?
可以使用cURL库,并设置Range头部。
php
$url = 'http://example.com/resource';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Range: bytes=-10'
));
$response = curl_exec($ch);
curl_close($ch);
echo $response;
十三、跨域请求时,如何解决
跨域请求(Cross-Origin Requests)指的是从一个源(协议、域名、端口三者组合)向另一个源发送的请求。由于安全原因,浏览器对跨域请求有严格的限制,称为同源策略(Same-Origin Policy)。
解决方法
- 在php脚本添加请求头
php
<?php
// 设置允许访问的域名
header("Access-Control-Allow-Origin: *");
// 设置允许的请求方法
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
// 设置允许的请求头
header("Access-Control-Allow-Headers: Content-Type, Authorization");
- 在nginx配置中添加请求头
十四、如何实现动态图片的生成和处理
可以使用 GD 库 或 Imagick 扩展。
动态生成或处理图片,通常有两大类场景:
- 生成新图片:验证码、缩略图、带水印的图片、统计图表等。
- 处理已有图片:裁剪、缩放、加文字/水印、调整格式或质量。
核心步骤是:
- 新建画布或加载已有资源
- 绘制/修改内容
- 输出图片并设置HTTP头
- 销毁资源
示例:
php
//载入
$img = imagecreatefrompng('1.png');
//设置字体颜色
$font_color = imagecolorallocate($img,0,0,0);
//imagestring ( resource $image , int $font , int $x , int $y , string $s , int $col ) : bool
//imagestring() 用 col 颜色将字符串 s 画到 image 所代表的图像的 x,y 坐标处(这是字符串左上角坐标,整幅图像的左上角为 0,0)。如果 font 是 1,2,3,4 或 5,则使用内置字体。
imagestring($img,5,0,0,"hello",$font_color);
header("Content-Type: image/png");
//输出
imagepng($img);
imagedestroy($img);