首页
关于
Search
1
给你10个市场数据调研报告的免费下载网站!以后竞品数据就从这里找!
182 阅读
2
php接口优化 使用curl_multi_init批量请求
144 阅读
3
《从菜鸟到大师之路 ElasticSearch 篇》
107 阅读
4
2024年备考系统架构设计师
104 阅读
5
PHP 文件I/O
92 阅读
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
累计撰写
786
篇文章
累计收到
28
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
100
篇与
的结果
2023-12-29
php 使用 WebDriver 模拟浏览器做采集示例
php 使用 WebDriver 模拟浏览器做采集示例随着互联网的普及,网站上的数据越来越丰富,从中获取有价值的信息对很多人来说越来越重要。而手动采集的效率和精度都不高,因此采用自动化脚本成为许多人选项之一。本文将介绍如何使用PHP语言结合WebDriver技术实现模拟浏览器做采集的方式。首先,我们需要了解什么是WebDriver。WebDriver是一个开放源代码项目,它提供了一组API来控制浏览器,从而能够实现自动化测试、数据挖掘等各种应用场景。Selenium是WebDriver的一个具体实现,它可以控制各种浏览器进行模拟操作。这里我们选择使用Selenium的PHP版,也就是php-webdriver,它能让我们用PHP语言来利用Selenium进行自动化测试。接下来我们需要安装php-webdriver。使用Composer进行安装,Composer是一个PHP依赖管理工具,能够帮助我们在项目中快速添加所需的库文件。打开命令行窗口,输入以下命令:composer require php-webdriver/webdriver安装完成后,在你的PHP代码中引入WebDriver:require_once 'vendor/autoload.php'; use Facebook\WebDriver; use Facebook\WebDriver\Remote; use Facebook\WebDriver\WebDriverBy;下面,我们来实现一个简单的采集网站的例子。假设我们要采集的网站是https://www.baidu.com,我们想要获取百度的搜索框、搜索按钮和搜索结果的标题文本。首先,我们需要创建一个WebDriver实例:$host = 'http://localhost:4444/wd/hub'; // Selenium Server的地址 $driver = Remote\RemoteWebDriver::create($host, Remote\DesiredCapabilities::chrome());这里我们使用了chrome浏览器。创建实例后,我们可以使用WebDriver打开指定的网站:$driver->get("https://www.baidu.com");接下来我们需要找到页面上的搜索框和搜索按钮,并输入关键字:$search_box = $driver->findElement(WebDriverBy::id('kw')); $search_box->sendKeys('WebDriver'); $search_button = $driver->findElement(WebDriverBy::id('su')); $search_button->click();WebDriver提供了多种查找元素的方式,这里我们使用了id来查找搜索框和按钮元素。sendKeys和click方法用于模拟在搜索框中输入内容和点击搜索按钮。最后,我们需要获取搜索结果中的标题文本。因为搜索结果是一系列的文本链接,我们可以找到它们的CSS选择器,并遍历它们。$results = $driver->findElements(WebDriverBy::cssSelector('#content_left .result .t a')); foreach ($results as $result) { echo $result->getText() . PHP_EOL; // 输出标题文本到控制台 }到这里,我们已经完成了一个简单的模拟浏览器做采集的示例。完整的代码如下:require_once 'vendor/autoload.php'; use Facebook\WebDriver; use Facebook\WebDriver\Remote; use Facebook\WebDriver\WebDriverBy; $host = 'http://localhost:4444/wd/hub'; // Selenium Server的地址 $driver = Remote\RemoteWebDriver::create($host, Remote\DesiredCapabilities::chrome()); $driver->get("https://www.baidu.com"); $search_box = $driver->findElement(WebDriverBy::id('kw')); $search_box->sendKeys('WebDriver'); $search_button = $driver->findElement(WebDriverBy::id('su')); $search_button->click(); $results = $driver->findElements(WebDriverBy::cssSelector('#content_left .result .t a')); foreach ($results as $result) { echo $result->getText() . PHP_EOL; } $driver->quit();总结:利用WebDriver技术,我们可以使用PHP语言来控制浏览器进行自动化操作,这对于采集信息、自动化测试等场景都有很大的帮助。要想运用好这项技术,除了掌握WebDriver的API之外,还需要对浏览器、页面结构等有一定的了解,这样才能写出高效、稳定的自动化脚本。
2023年12月29日
13 阅读
0 评论
0 点赞
2023-12-29
代码重构三个原则和技巧
代码重构三个原则和技巧随着业务需求不断改变和代码规模的扩大,PHP应用程序中出现代码重复和冗余的问题是很常见的。代码重复和冗余不仅增加了代码的维护成本,也会降低代码的可读性和可维护性。如果不采取有效的措施解决这些问题,最终可能会导致系统稳定性和应用程序的性能问题。在本文中,我们将探讨使用代码重构技巧来消除PHP代码中的重复和冗余的方法。我们将深入研究代码重构的原则和技巧,并提供有关如何重构PHP代码的实用示例。我们的目标是提高PHP应用程序的可读性,可维护性和性能,同时降低代码维护成本。原则和技巧在进行代码重构之前,请仔细思考以下原则和技巧。这些原则和技巧将帮助您快速准确地确定哪些代码需要重构,以及应该如何重构。1.遵循DRY原则DRY原则,即“不要重复自己”的原则,是代码重构的核心原则。DRY原则强调的是,在代码中尽可能避免重复和冗余,并且尽量将复杂逻辑抽象为可重用的组件。当应用程序中出现重复和冗余代码时,往往需要同时修改多个地方,这将耗费大量的时间和精力,并且还会导致出现错误的可能。因此,遵循DRY原则非常重要,可以有效地减少代码重复和冗余,并提高代码的可读性和可维护性。2.使用函数和类使用函数和类是遵循DRY原则的最佳方式,因为它们可以抽象出可重用的代码段,将复杂逻辑封装起来,减少代码冗余,并提高代码的可读性和可维护性。通过函数和类,可以将重复和冗余的代码分离出来,并将它们放在一个单独的代码块中,从而方便维护。3.采用命名规范在重构代码时,为变量、函数和类采用清晰、简洁的命名规范非常重要。这有助于代码的可读性和可维护性,并且可以减少因代码混淆而带来的不必要问题。通常,命名规范应该尽可能地简洁明了,包含有意义的名称,避免使用简写或缩写,以及避免使用具有多种含义的词汇。使用一致的命名规范还可以方便代码的维护和追踪。示例下面我们来看几个实际的示例,说明如何使用代码重构来消除PHP代码中的重复和冗余。1.使用函数和类假设我们有一个以下代码,用于计算两个日期之间的天数:$startDate = strtotime('2021-01-01'); $endDate = strtotime('2021-01-31'); $days = floor(($endDate - $startDate) / 86400); echo "Days between: $days";在这个例子中,我们使用了strtotime()函数来将字符串日期转换为时间戳,并且使用86400来表示一天的秒数。但是,这个计算天数的代码在不同的地方会被重复使用,因此它违反了DRY原则。为了消除这种重复,我们可以将它封装在一个单独的函数中:function calculateDaysBetween($startDate, $endDate) { $days = floor(($endDate - $startDate) / 86400); return $days; } $startDate = strtotime('2021-01-01'); $endDate = strtotime('2021-01-31'); $days = calculateDaysBetween($startDate, $endDate); echo "Days between: $days";在这个例子中,我们将计算天数的逻辑封装在了一个名为calculateDaysBetween()的函数中,这样我们可以在需要时轻松地调用它,而无需重复编写相同的逻辑。通过这种重构方式,我们遵循了DRY原则,并且提高了代码的可读性、可维护性和可重用性。2.减少条件语句在很多PHP应用程序中,条件语句可能会变得非常冗长和复杂。在这种情况下,当需要对代码进行修改和维护时,它们会变得非常难以理解。下面是一个简单的示例,用于在条件语句中使用逻辑或运算符:if($a == 1 || $a == 2 || $a == 3) { // do something }在这个示例代码中,使用逻辑或运算符连接了多个条件语句。这种代码可能很难理解和维护,因此我们可以使用in_array()函数来简化条件语句:if(in_array($a, [1, 2, 3])) { // do something }通过这种重构方式,我们使用一个in_array()函数来代替了冗长的条件语句,使代码更易于理解和维护。3.引入配置文件在PHP应用程序中,可能会使用很多硬编码的字符串和常量。这些字符串和常量通常用于定义数据库连接信息、网站地址等。下面是一个简单的示例,展示如何使用硬编码的字符串来定义数据库连接信息:$link = mysqli_connect("localhost", "admin", "123456", "my_db");这样的代码可能很难维护,因为这些硬编码的字符串分散在不同的代码文件中,并且可能需要在多个地方进行修改。为了消除这种冗余,我们可以使用一个单独的配置文件来定义这些字符串和常量。在这个配置文件中,我们可以定义一个数组,包含了所有的连接信息,如下所示:$config = [ 'db_host' => 'localhost', 'db_user' => 'admin', 'db_pass' => '123456', 'db_name' => 'my_db' ]; 然后,在代码中,我们可以使用这个配置数组来定义和连接数据库,如下所示:$link = mysqli_connect($config['db_host'], $config['db_user'], $config['db_pass'], $config['db_name']);通过这种重构方式,我们将数据库连接信息定义在单独的配置文件中,从而避免了代码重复和冗余,并且使得这些信息更容易维护和修改。结论在本文中,我们介绍了一些有效的代码重构技巧,以消除PHP应用程序中的重复和冗余。使用这些技巧,我们可以通过遵循DRY原则,使用函数和类,减少条件语句和引入配置文件等方法来提高代码的可读性、可维护性和性能,并且降低代码维护成本。在实际开发中,代码重构是一个非常重要的任务。通过持续地优化和重构代码,我们可以使其更加精简、高效,提高代码的质量和可维护性,从而使我们的应用程序更加稳定、可靠。
2023年12月29日
12 阅读
0 评论
0 点赞
2023-12-28
用PHP自己动手写MVC框架,彻底搞懂MVC结构!
php中文网 php中文网课程 2023-03-30 17:00 发表于安徽高效开发离不开框架的辅助,掌握主流PHP开发框架的使用, 是每一名PHP程序员必备的基本技能,想掌握框架开发,最快的方法,就是知道框架底层的运行原理是什么,编程思想是什么? 而自己动手写一个框架, 则是公认的,最快的框架学习方法!本套课程用最直白的语言,最简单的案例,让你在不知不觉中学会自己写一个小框架(MVC)!(2022年10月份最新录制实战课,共40节)课程内容开发环境准备与搭建PHP框架简介与MVC思想URL-路由-伪静态原理神奇的$_SERVER变量公共函数库模型之数据库静态委托编写配置项与引入方式细说数据库查询类Query关于ORDER排序的补充说明视图类基本功能详解控制器类的基本功能路由类的基本功能与实现入口文件功能与编写方法框架启动类功能详解项目调试开关的打开与关闭项目总结与进阶建议学习地址https://www.php.cn/course/1467.html
2023年12月28日
11 阅读
0 评论
0 点赞
2023-12-19
MySQL 优化
MySQL 优化MySQL 优化导入的优化insert 的优化group by 的优化order by 的优化优化嵌套查询count 的优化limit 分页的优化SQL 中 IN 包含的值不应该太多只需要一条数据的情况如果没有使用索引,就尽量减少排序尽量用 union all 来代替 unionwhere 条件优化查询时,尽量指定查询的字段名MySQL 分析表MySQL 检查表MySQL 优化表索引介绍索引分类索引使用查看索引的使用情况索引使用细则通过 show status 命令了解 SQL 执行次数定位执行效率较低的 SQL通过 EXPLAIN 命令分析 SQL 的执行计划SQL 优化步骤索引MySQL 分析表、检查表和优化表常用 SQL 优化一般传统互联网公司很少接触到 SQL 优化问题,其原因是数据量小,大部分厂商的数据库性能能够满足日常的业务需求,所以不需要进行 SQL 优化,但是随着应用程序的不断变大,数据量的激增,数据库自身的性能跟不上了,此时就需要从 SQL 自身角度来进行优化,这也是我们这篇文章所讨论的。SQL 优化步骤当面对一个需要优化的 SQL 时,我们有哪几种排查思路呢?通过 show status 命令了解 SQL 执行次数首先,我们可以使用 show status 命令查看服务器状态信息。show status 命令会显示每个服务器变量 variable_name 和 value,状态变量是只读的。如果使用 SQL 命令,可以使用 like 或者 where 条件来限制结果。like 可以对变量名做标准模式匹配。图我没有截全,下面还有很多变量,读者可以自己尝试一下。也可以在操作系统上使用 mysqladmin extended-status 命令来获取这些消息。但是我执行 mysqladmin extended-status 后,出现这个错误。应该是我没有输入密码的原因,使用 mysqladmin -P3306 -uroot -p -h127.0.0.1 -r -i 1 extended-status 后,问题解决。这里需要注意一下 show status 命令中可以添加统计结果的级别,这个级别有两个session 级: 默认当前链接的统计结果global 级:自数据库上次启动到现在的统计结果如果不指定统计结果级别的话,默认使用 session 级别。对于 show status 查询出来的统计结果,有两类参数需要注意下,一类是以 Com_ 为开头的参数,一类是以 Innodb_ 为开头的参数。下面是 Com_ 为开头的参数,参数很多,我同样没有截全。Com_xxx 表示的是每个 xxx 语句执行的次数,我们通常关心的是 select 、insert 、update、delete 语句的执行次数,即Com_select:执行 select 操作的次数,一次查询会使结果 + 1。Com_insert:执行 INSERT 操作的次数,对于批量插入的 INSERT 操作,只累加一次。Com_update:执行 UPDATE 操作的次数。Com_delete:执行 DELETE 操作的次数。以 Innodb_ 为开头的参数主要有Innodb_rows_read:执行 select 查询返回的行数。Innodb_rows_inserted:执行 INSERT 操作插入的行数。Innodb_rows_updated:执行 UPDATE 操作更新的行数。Innodb_rows_deleted:执行 DELETE 操作删除的行数。通过上面这些参数执行结果的统计,我们能够大致了解到当前数据库是以更新(包括插入、删除)为主还是查询为主。除此之外,还有一些其他参数用于了解数据库的基本情况。Connections:查询 MySQL 数据库的连接次数,这个次数是不管连接是否成功都算上。Uptime:服务器的工作时间。Slow_queries:满查询次数。Threads_connected:查看当前打开的连接的数量。下面这个博客汇总了几乎所有 show status 的参数,可以当作参考手册。https://blog.csdn.net/ayay_870621/article/details/88633092定位执行效率较低的 SQL定位执行效率比较慢的 SQL 语句,一般有两种方式可以通过慢查询日志来定位哪些执行效率较低的 SQL 语句。MySQL 中提供了一个慢查询的日志记录功能,可以把查询 SQL 语句时间大于多少秒的语句写入慢查询日志,日常维护中可以通过慢查询日志的记录信息快速准确地判断问题所在。用 --log-slow-queries 选项启动时,mysqld 会写一个包含所有执行时间超过 long_query_time 秒的 SQL 语句的日志文件,通过查看这个日志文件定位效率较低的 SQL 。比如我们可以在 my.cnf 中添加如下代码,然后退出重启 MySQL。log-slow-queries = /tmp/mysql-slow.loglong_query_time = 2通常我们设置最长的查询时间是 2 秒,表示查询时间超过 2 秒就记录了,通常情况下 2 秒就够了,然而对于很多 WEB 应用来说,2 秒时间还是比较长的。也可以通过命令来开启:我们先查询 MySQL 慢查询日志是否开启show variables like "%slow%";启用慢查询日志set global slow_query_log='ON';然后再次查询慢查询是否开启如图所示,我们已经开启了慢查询日志。慢查询日志会在查询结束以后才记录,所以在应用反应执行效率出现问题的时候慢查询日志并不能定位问题,此时应该使用 show processlist 命令查看当前 MySQL 正在进行的线程。包括线程的状态、是否锁表等,可以实时的查看 SQL 执行情况。同样,使用mysqladmin processlist语句也能得到此信息。下面就来解释一下各个字段对应的概念Id :Id 就是一个标示,在我们使用 kill 命令杀死进程的时候很有用,比如 kill 进程号。User:显示当前的用户,如果不是 root,这个命令就只显示你权限范围内的 SQL 语句。Host:显示 IP ,用于追踪问题Db:显示这个进程目前连接的是哪个数据库,为 null 是还没有 select 数据库。Command:显示当前连接锁执行的命令,一般有三种:查询 query,休眠 sleep,连接 connect。Time:这个状态持续的时间,单位是秒State:显示当前 SQL 语句的状态,非常重要,下面会具体解释。Info:显示这个 SQL 语句。State 列非常重要,关于这个列的内容比较多,读者可以参考一下这篇文章https://blog.csdn.net/weixin_34357436/article/details/91768402这里面涉及线程的状态、是否锁表等选项,可以实时的查看 SQL 的执行情况,同时对一些锁表进行优化。通过 EXPLAIN 命令分析 SQL 的执行计划通过以上步骤查询到效率低的 SQL 语句后,可以通过 EXPLAIN 或者 DESC 命令获取 MySQL 如何执行 SELECT 语句的信息,包括在 SELECT 语句执行过程中表如何连接和连接的顺序。比如我们使用下面这条 SQL 语句来分析一下执行计划explain select * from test1;上表中涉及内容如下select_type:表示常见的 SELECT 类型,常见的有 SIMPLE,SIMPLE 表示的是简单的 SQL 语句,不包括 UNION 或者子查询操作,比如下面这段就是 SIMPLE 类型。PRIMARY ,查询中最外层的 SELECT(如两表做 UNION 或者存在子查询的外层的表操作为 PRIMARY,内层的操作为 UNION),比如下面这段子查询。UNION,在 UNION 操作中,查询中处于内层的 SELECT(内层的 SELECT 语句与外层的 SELECT 语句没有依赖关系时)。SUBQUERY:子查询中首个SELECT(如果有多个子查询存在),如我们上面的查询语句,子查询第一个是 sr(sys_role)表,所以它的 select_type 是 SUBQUERY。table ,这个选项表示输出结果集的表。type,这个选项表示表的连接类型,这个选项很有深入研究的价值,因为很多 SQL 的调优都是围绕 type 来讲的,但是这篇文章我们主要围绕优化方式来展开的,type 这个字段我们暂时作为了解,这篇文章不过多深入。type 这个字段会牵扯到连接的性能,它的不同类型的性能由好到差分别是system :表中仅有一条数据时,该表的查询就像查询常量表一样。const :当表中只有一条记录匹配时,比如使用了表主键(primary key)或者表唯一索引(unique index)进行查询。eq-ref :表示多表连接时使用表主键或者表唯一索引,比如select A.text, B.text where A.ID = B.ID这个查询语句,对于 A 表中的每一个 ID 行,B 表中都只能有唯一的 B.Id 来进行匹配时。ref :这个类型不如上面的 eq-ref 快,因为它表示的是因为对于表 A 中扫描的每一行,表 C 中有几个可能的行,C.ID 不是唯一的。ref_or_null :与 ref 类似,只不过这个选项包含对 NULL 的查询。index_merge :查询语句使用了两个以上的索引,比如经常在有 and 和 or 关键字出现的场景,但是在由于读取索引过多导致其性能有可能还不如 range(后面说)。unique_subquery :这个选项经常用在 in 关键字后面,子查询带有 where 关键字的子查询中,用 sql 来表示就是这样value IN (SELECT primary_key FROM single_table WHERE some_expr)range :索引范围查询,常见于使用 =,<>,>,>=,<,<=,IS NULL,<=>,BETWEEN,IN() 或者 like 等运算符的查询中。index :索引全表扫描,把索引从头到尾扫一遍。all : 这个我们接触的最多了,就是全表查询,select * from xxx ,性能最差。上面就是 type 内容的大致解释,关于 type 我们经常会在 SQL 调优的环节使用 explain 分析其类型,然后改进查询方式,越靠近 system 其查询效率越高,越靠近 all 其查询效率越低。possible_keys :表示查询时,可能使用的索引。key :表示实际使用的索引。key_len :索引字段的长度。rows :扫描行的数量。filtered :通过查询条件查询出来的 SQL 数量占用总行数的比例。extra :执行情况的描述。通过上面的分析,我们可以大致确定 SQL 效率低的原因,一种非常有效的提升 SQL 查询效率的方式就是使用索引,接下来我会讲解一下如何使用索引提高查询效率。索引索引是数据库优化中最常用也是最重要的手段,通过使用不同的索引可以解决大多数 SQL 性能问题,也是面试经常会问到的优化方式,围绕着索引,面试官能让你造出火箭来,所以总结一点就是索引非常非常重!要!不只是使用,你还要懂其原!理!索引介绍索引的目的就是用于快速查找某一列的数据,对相关数据列使用索引能够大大提高查询操作的性能。不使用索引,MySQL 必须从第一条记录开始读完整个表,直到找出相关的行,表越大查询数据所花费的时间就越多。如果表中查询的列有索引,MySQL 能够快速到达一个位置去搜索数据文件,而不必查看所有数据,那么将会节省很大一部分时间。索引分类先来了解一下索引都有哪些分类。全局索引(FULLTEXT):全局索引,目前只有 MyISAM 引擎支持全局索引,它的出现是为了解决针对文本的模糊查询效率较低的问题,并且只限于 CHAR、VARCHAR 和 TEXT 列。哈希索引(HASH):哈希索引是 MySQL 中用到的唯一 key-value 键值对的数据结构,很适合作为索引。HASH 索引具有一次定位的好处,不需要像树那样逐个节点查找,但是这种查找适合应用于查找单个键的情况,对于范围查找,HASH 索引的性能就会很低。默认情况下,MEMORY 存储引擎使用 HASH 索引,但也支持 BTREE 索引。B-Tree 索引:B 就是 Balance 的意思,BTree 是一种平衡树,它有很多变种,最常见的就是 B+ Tree,它被 MySQL 广泛使用。R-Tree 索引:R-Tree 在 MySQL 很少使用,仅支持 geometry 数据类型,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种,相对于 B-Tree 来说,R-Tree 的优势在于范围查找。从逻辑上来对 MySQL 进行分类,主要分为下面这几种普通索引:普通索引是最基础的索引类型,它没有任何限制 。创建方式如下create index normal_index on cxuan003(id);删除方式drop index normal_index on cxuan003;唯一索引:唯一索引列的值必须唯一,允许有空值,如果是组合索引,则列值的组合必须唯一,创建方式如下create unique index normal_index on cxuan003(id);主键索引:是一种特殊的索引,一个表只能有一个主键,不允许有空值。一般是在建表的时候同时创建主键索引。CREATE TABLE \`table\` ( \`id\` int(11) NOT NULL AUTO_INCREMENT , \`title\` char(255) NOT NULL , PRIMARY KEY (\`id\`) )组合索引:指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀原则,下面我们就会创建组合索引。全文索引:主要用来查找文本中的关键字,而不是直接与索引中的值相比较,目前只有 char、varchar,text 列上可以创建全文索引,创建表的适合添加全文索引CREATE TABLE \`table\` ( \`id\` int(11) NOT NULL AUTO_INCREMENT , \`title\` char(255) CHARACTER NOT NULL , \`content\` text CHARACTER NULL , \`time\` int(10) NULL DEFAULT NULL , PRIMARY KEY (\`id\`), FULLTEXT (content) );当然也可以直接创建全局索引CREATE FULLTEXT INDEX index_content ON article(content)索引使用索引可以在创建表的时候进行创建,也可以单独创建,下面我们采用单独创建的方式,我们在 cxuan004 上创建前缀索引我们使用 explain 进行分析,可以看到 cxuan004 使用索引的情况如果不想使用索引,可以删除索引,索引的删除语法是索引使用细则我们在 cxuan005 上根据 id 和 hash 创建一个复合索引,如下所示create index id_hash_index on cxuan005(id,hash);然后根据 id 进行执行计划的分析explain select * from cxuan005 where id = '333';可以发现,即使 where 条件中使用的不是复合索引(Id 、hash),索引仍然能够使用,这就是索引的前缀特性。但是如果只按照 hash 进行查询的话,索引就不会用到。explain select * from cxuan005 where hash='8fd1f12575f6b39ee7c6d704eb54b353';如果 where 条件使用了 like 查询,并且 % 不在第一个字符,索引才可能被使用。对于复合索引来说,只能使用 id 进行 like 查询,因为 hash 列不管怎么查询都不会走索引。explain select * from cxuan005 where id like '%1';可以看到,如果第一个字符是 % ,则没有使用索引。explain select * from cxuan005 where id like '1%';如果使用了 % 号,就会触发索引。如果列名是索引的话,那么对列名进行 NULL 查询,将会触发索引。explain select * from cxuan005 where id is null;还有一些情况是存在索引但是 MySQL 并不会使用的情况。最简单的,如果使用索引后比不使用索引的效率还差,那么 MySQL 就不会使用索引。如果 SQL 中使用了 OR 条件,OR 前的条件列有索引,而后面的列没有索引的话,那么涉及到的索引都不会使用,比如 cxuan005 表中,只有 id 和 hash 字段有索引,而 info 字段没有索引,那么我们使用 or 进行查询。explain select * from cxuan005 where id = 111 and info = 'cxuan';我们从 explain 的执行结果可以看到,虽然 possible_keys 选项上仍然有 id_hash_index 索引,但是从 key、key_len 可以得知,这条 SQL 语句并未使用索引。在带有复合索引的列上查询不是第一列的数据,也不会使用索引。explain select * from cxuan005 where hash = '8fd1f12575f6b39ee7c6d704eb54b353';如果 where 条件的列参与了计算,那么也不会使用索引explain select * from cxuan005 where id + '111' = '666';索引列使用函数,一样也不会使用索引explain select * from cxuan005 where concat(id,'111') = '666';索引列使用了 like ,并且 % 位于第一个字符,则不会使用索引。在 order by 操作中,排序的列同时也在 where 语句中,将不会使用索引。当数据类型出现隐式转换时,比如 varchar 不加单引号可能转换为 int 类型时,会使索引无效,触发全表扫描。比如下面这两个例子能够显而易见的说明这一点在索引列上使用 IS NOT NULL 操作在索引字段上使用 <>,!=。不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。关于设置索引但是索引没有生效的场景还有很多,这个需要小伙伴们工作中不断总结和完善,不过我上面总结的这些索引失效的情景,能够覆盖大多数索引失效的场景了。查看索引的使用情况在 MySQL 索引的使用过程中,有一个 Handler_read_key 值,这个值表示了某一行被索引值读的次数。 Handler_read_key 的值比较低的话,则表明增加索引得到的性能改善不是很理想,可能索引使用的频率不高。还有一个值是 Handler_read_rnd_next,这个值高则意味着查询运行效率不高,应该建立索引来进行抢救。这个值的含义是在数据文件中读下一行的请求数。如果正在进行大量的表扫描,Handler_read_rnd_next 的值比较高,就说明表索引不正确或写入的查询没有利用索引。MySQL 分析表、检查表和优化表对于大多数开发者来说,他们更倾向于解决简单 SQL的优化,而复杂 SQL 的优化交给了公司的 DBA 来做。下面就从普通程序员的角度和你聊几个简单的优化方式。MySQL 分析表分析表用于分析和存储表的关键字分布,分析的结果可以使得系统得到准确的统计信息,使得 SQL 生成正确的执行计划。如果用于感觉实际执行计划与预期不符,可以执行分析表来解决问题,分析表语法如下analyze table cxuan005;分析结果涉及到的字段属性如下Table:表示表的名称;Op:表示执行的操作,analyze 表示进行分析操作,check 表示进行检查查找,optimize 表示进行优化操作;Msg_type:表示信息类型,其显示的值通常是状态、警告、错误和信息这四者之一;Msg_text:显示信息。对表的定期分析可以改善性能,应该成为日常工作的一部分。因为通过更新表的索引信息对表进行分析,可改善数据库性能。MySQL 检查表数据库经常可能遇到错误,比如数据写入磁盘时发生错误,或是索引没有同步更新,或是数据库未关闭 MySQL 就停止了。遇到这些情况,数据就可能发生错误: Incorrect key file for table: ' '. Try to repair it. 此时,我们可以使用 Check Table 语句来检查表及其对应的索引。check table cxuan005;检查表的主要目的就是检查一个或者多个表是否有错误。Check Table 对 MyISAM 和 InnoDB 表有作用。Check Table 也可以检查视图的错误。MySQL 优化表MySQL 优化表适用于删除了大量的表数据,或者对包含 VARCHAR、BLOB 或则 TEXT 命令进行大量修改的情况。MySQL 优化表可以将大量的空间碎片进行合并,消除由于删除或者更新造成的空间浪费情况。它的命令如下optimize table cxuan005;我的存储引擎是 InnoDB 引擎,但是从图可以知道,InnoDB 不支持使用 optimize 优化,建议使用 recreate + analyze 进行优化。optimize 命令只对 MyISAM 、BDB 表起作用。常用 SQL 优化前面我们介绍了使用索引来优化 MySQL ,那么对于 SQL 的各种语法,句法来说,应该怎样优化呢?下面,我会从 SQL 命令的角度来聊一波 SQL 优化。导入的优化对于 MyISAM 类型的表,可以通过下面这种方式导入大量的数据ALTER TABLE tblname DISABLE KEYS; loading the dataALTER TABLE tblname ENABLE KEYS;这两个命令用来打开或者关闭 MyISAM 表非唯一索引的更新。在导入大量的数据到一个非空的 MyISAM 表时,通过设置这两个命令,可以提高导入的效率。对于导入大量数据到一个空的 MyISAM 表,默认就是先导入数据然后才创建索引,所以不用进行设置。但是对于 InnoDB 搜索引擎的表来说,这样做不能提高导入效率,我们有以下几种方式可以提高导入的效率:因为 InnoDB 类型的表是按照主键的顺序保存的,所以将导入的数据按照主键的顺序排列,可以有效的提高导入数据的效率。如果 InnoDB 表没有主键,那么系统会默认创建一个内部列作为主键,所以如果可以给表创建一个主键,将可以利用这个优势提高导入数据的效率。在导入数据前执行 SET UNIQUE_CHECKS = 0,关闭唯一性校验,在导入结束后执行SETUNIQUE_CHECKS = 1,恢复唯一性校验,可以提高导入的效率。如果应用使用自动提交的方式,建议在导入前执行 SET AUTOCOMMIT = 0,关闭自动提交,导入结束后再执行 SET AUTOCOMMIT = 1,打开自动提交,也可以提高导入的效率。insert 的优化当进行插入语句的时候,可以考虑采用下面这几种方式进行优化如果向同一张表插入多条数据的话,最好一次性插入,这样可以减少数据库建立连接 -\> 断开连接的时间,如下所示insert into test values(1,2),(1,3),(1,4)如果向不同的表插入多条数据,可以使用 insert delayed 语句提高执行效率。delayed 的含义是让 insert 语句马上执行,要么数据都会放在内存的队列中,并没有真正写入磁盘。对于 MyISAM 表来说,可以增加 bulk_insert_buffer_size 的值提高插入效率。最好将索引和数据文件在不同的磁盘上存放。group by 的优化在使用分组和排序的场景下,如果先进行 Group By 再进行 Order By 的话,可以指定 order by null 禁止排序,因为 order by null 可以避免 filesort ,filesort 往往很耗费时间。如下所示explain select id,sum(moneys) from sales2 group by id order by null;order by 的优化在执行计划中,经常可以看到 Extra 列出现了 filesort,filesort 是一种文件排序,这种排序方式比较慢,我们认为是不好的排序,需要进行优化。优化的方式是要使用索引。我们在 cxuan005 上创建一个索引。create index idx on cxuan005(id);然后我们使用查询字段和排序相同的顺序进行查询。explain select id from cxuan005 where id > '111' order by id;可以看到,在这次查询中,使用的是 Using index。这表明我们使用的是索引。如果创建索引和 order by 的顺序不一致,将会使用 Using filesort。explain select id from cxuan005 where id > '111' order by info;MySQL 支持两种方式的排序,filesort 和 index,Using index 是指 MySQL 扫描索引本身完成排序。index 效率高,filesort 效率低。order by 在满足下面这些情况下才会使用 indexorder by 语句使用索引最左前列。使用 where 子句与 order by 子句条件列组合满足索引最左前列。优化嵌套查询嵌套查询是我们经常使用的一种查询方式,这种查询方式可以使用 SELECT 语句来创建一个单独的查询结果,然后把这个结果当作嵌套语句的查询范围用在另一个查询语句中。使用时子查询可以将一个复杂的查询拆分成一个个独立的部分,逻辑上更易于理解以及代码的维护和重复使用。但是某些情况下,子查询的效率不高,一般使用 join 来替代子查询。使用嵌套查询的 SQL 语句进行 explain 分析如下explain select c05.id from cxuan005 c05 where id not in (select id from cxuan003);从 explain 的结果可以看出,主表的查询是 index ,子查询是 index_subquery ,这两个执行效率都不高。我们使用 join 来优化后的分析计划如下。explain select c05.id from cxuan005 c05 left join cxuan003 c03 on c05.id = c03.id;从 explain 分析结果可以看到,主表查询和子查询分别是 index 和 ref,而 ref 的执行效率相对较高,一般 type 的效率由高到低是 System-->const-->eq_ref-->ref--> fulltext-->ref_or_null-->index_merge-->unique_subquery-->index_subquery-->range-->index-->all 。count 的优化count 我们大家用的太多了,一般都用来统计某一列结果集的行数,当 MySQL 确认括号内的表达式不可能为空时,实际上就是在统计行数。其实 count 还有另一层统计方式:统计某个列值的数量,在统计列值数量的时候,它默认不会统计 NULL 值。我们经常犯的一个错误就是,在括号内指定一个列但是却希望统计结果集的行数。如果想要知道结果集行数的话,最好使用 count(*)。limit 分页的优化通常我们的系统会进行分页,一般情况下我们会使用 limit 加上偏移量来实现。同时还会加上 order by 语句进行排序。如果使用索引的情况下,效率一般不会有什么问题,如果没有使用索引的话,MySQL 就可能会做大量的文件排序操作。通常我们可能会遇到比如 limit 1000 , 50 这种情况,抛弃 1000 条,只取 50 条,这样的代价非常高,如果所有页面被访问的频率相同,那么这样的查询平均需要访问半个表的数据。要优化这种查询,要么限制分页的数量,要么优化大偏移量的性能。SQL 中 IN 包含的值不应该太多MySQL 中对 IN 做了相应的优化,MySQL 会将全部的常量存储在一个数组里面,如果数值较多,产生的消耗也会变大,比如select name from dual where num in(4,5,6)像这种 SQL 语句的话,能用 between 使用就不要再使用 in 了。只需要一条数据的情况如果只需要一条数据的情况下,推荐使用 limit 1,这样会使执行计划中的 type 变为 const。如果没有使用索引,就尽量减少排序尽量用 union all 来代替 unionunion 和 union all 的差异主要是前者需要将结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的 CPU 运算,加大资源消耗及延迟。当然,union all 的前提条件是两个结果集没有重复数据。where 条件优化避免在 WHERE 字句中对字段进行 NULL 判断避免在 WHERE 中使用 != 或 <> 操作符不建议使用 % 前缀模糊查询,例如 LIKE “%name”或者LIKE “%name%”,这种查询会导致索引失效而进行全表扫描。但是可以使用LIKE “name%”。避免在 where 中对字段进行表达式操作,比如 select user_id,user_project from table_name where age*2=36 就是一种表达式操作,建议改为 select user_id,user_project from table_name where age=36/2 建议在 where 子句中确定 column 的类型,避免 column 字段的类型和传入的参数类型不一致的时候发生的类型转换。查询时,尽量指定查询的字段名我们在日常使用 select 查询时,尽量使用 select 字段名 这种方式,避免直接 select * ,这样增加很多不必要的消耗(cpu、io、内存、网络带宽);而且查询效率比较低。
2023年12月19日
12 阅读
0 评论
0 点赞
2023-12-18
phpy :PHP 与 Python 互调用库,为 PHP 引入 Python 生态,PHP 也可以写 AI 了
phpy :PHP 与 Python 互调用库,为 PHP 引入 Python 生态,PHP 也可以写 AI 了phpy 是识沃团队最新推出的开源项目,目标是为 PHP 引入 Python 生态,来弥补 PHP 生态的空缺和不足。phpy 使得 PHP 可以调用所有 Python 的包。包括当下非常流行的 PyTorch、transformers、TensorFlow 等 AI 库,以及 Numpy、Pandas、Scikit 等科学计算库,还可以使用 PyQt、wxPython 等图形界面库。GitHub 地址:https://github.com/swoole/phpy不建议在 php-fpm/apache 短生命周期运行环境下使用,频繁地导入/销毁模块的开销会消耗大量资源编译安装phpy 可以作为 PHP 的扩展,也可以作为 Python 的 C 模块。既可以在 PHP 代码中调用 Python 的库,也可以在 Python 中调用 PHP 的类和函数。作为 Python 模块时依赖 PHP 的 embed SAPI ,检查 PHP 的目录中,确保存在 libphp.soll /opt/php-8.1/lib/libphp.so -rwxr-xr-x 1 htf htf 39397224 11月 30 19:25 /opt/php-8.1/lib/libphp.so*编译依赖Python 3.10 或以上版本,建议使用 conda 工具来安装PHP 8.1 或以上版本Python 将安装到 /opt/anaconda3 目录下/opt/anaconda3/bin/python`Python` 主程序/opt/anaconda3/include/python3.11 头文件/opt/anaconda3/lib/python3.11 动态链接库目录另外需要配置 /etc/ld.so.conf.d/conda.conf 加入 /opt/anaconda3/lib 和 /opt/php-8.1/lib 。执行 ldconfig 检查是否可以找到 libpython3.11.so 和 libphp.so。sudo ldconfig -p |grep php libphp7.so (libc6,x86-64) => /opt/php-7.4/lib/libphp7.so libphp.so (libc6,x86-64) => /opt/php-8.0/lib/libphp.so sudo ldconfig -p |grep python libsamba-policy.cpython-38-x86-64-linux-gnu.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libsamba-policy.cpython-38-x86-64-linux-gnu.so.0 libpython3.11.so.1.0 (libc6,x86-64) => /opt/anaconda3/lib/libpython3.11.so.1.0 libpython3.11.so (libc6,x86-64) => /opt/anaconda3/lib/libpython3.11.so libpython3.8.so.1.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libpython3.8.so.1.0 libpython3.8.so (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libpython3.8.so libpython3.5m.so.1.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0 libpython3.so (libc6,x86-64) => /opt/anaconda3/lib/libpython3.so libpython2.7.so.1.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 libpython2.7.so (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libpython2.7.so作为 PHP 扩展检查 config.m4 中 Python 路径是否正确。若 Python 的安装路径不是 /opt/anaconda3,需修改为正确的安装路径。cd phpy phpize ./configure make install安装成功后,修改 php.ini ,加入 extension=phpy.so,执行 php -m 和 php --ri phpy 检查是否成功加载扩展。作为 Python 模块cmake . make -j执行成功后,会生成 tests/lib/phpy.so 文件。可以在 Python 中直接导入此模块。import phpy使用方法导入 Python 模块$os = PyCore::import('os');执行函数$uname = $os->uname();读取属性echo $uname->sysname;加载路径可使用 PyCore::import('sys')->path->append() 将一些目录加入到加载路径列表中。 例如:/workspace/app/user.py 自定义的包,可以通过下面的步骤实现加载:PyCore::import('sys')->path->append('/workspace') 将 /workspace 添加到 sys.path 中PyCore::import('app.user') 将自动搜索 sys.path 找到对应的 app/user.py 包并载入内置方法PyCore::str() 将对象转为字符串PyCore::repr()PyCore::type() 获取对象的类型PyCore::locals() 获取当前空间内容的所有局部变量PyCore::globals() 获取所有全局变量PyCore::hash() 获取 Hash 值PyCore::hasattr() 检测对象是否存在某个属性PyCore::id() 获取对象的内部编号PyCore::len() 获取长度PyCore::dir() 获取对象所有的属性、方法PyCore::int() 构造一个整数PyCore::float() 构造一个浮点数PyCore::fn() 构造一个可调用函数PyCore::scalar() 将 PyObject 对象转为 PHP 的标量类型,例如 PyStr 将转为 PHP 字符串,Dict/Tuple/Set/List 将转为 Array内置类PyObject:所有其他类型的基类PyDict:字典类型,等同于 PHP 的关联数组PyList:列表类型,等同于 PHP 的索引数组PyTuple:元组,不可变的列表PyStr:字符串PyModule:Python 包,PyModule 也是 PyObject 的子类PyObject 是除了 PyCore 之外,所有其他类型的基类。非内置类的对象是 PyObject 的实例。PyObject 实现了 4 个魔术方法,用于将操作映射到 Python 对象。所有类方法、参数、返回值参考 stubs 目录中的文件。继承关系PyObject -> PyModule -> PySequenece -> PyList -> PyTuple -> PySet -> PyStr -> PyDict -> PyType整数Python 语言是天然支持无限精度整型计算的,可以使用 Python 的整数计算能力来代替 ext-bcmath构造使用 PyCore::int() 函数来构造一个数字,可以传入整数、浮点数、字符串来初始化。$i1 = PyCore::int(12345678);$i2 = PyCore::int('1234567890123456789012345678901234567890');$i3 = PyCore::int(12345678.03);运算整数同样也是 PyObject 的实例,可以使用内置的方法类实现运算。$i = PyCore::int(12345435);var_dump(strval($i->__pow__(3)));var_dump(strval($i->__add__(4)));将输出 1881564851360655187875 ,由于超过了 64位 最大精度,因此输出结果将自动转为字符串类型。命名参数phpy 支持了命名参数,可以使用命名参数来调用 Python 的函数和方法。顺序参数必须在前,命名参数必须在最后kwargs($a, $b, $c, name: 'hello', world: 'rango');对应的 Python 代码为:kwargs(a, b, c, name: 'hello', world: 'rango')回调函数可将 PHP 的可调用对象作为 Python 的回调函数。使用 PyCore::fn(callable $fn) 包裹即可。$m = PyCore::import('app.user');$uuid = uniqid();$rs = $m->test_callback(PyCore::fn(function ($namespace) use ($uuid) { var_dump($namespace); return $uuid;}));import app.user 导入了一个自定义 Python 包调用了包中的一个函数 test_callback,此函数接受一个参数为 Python Callable 对象使用 PyCore::fn() 包裹了一个 Closure 闭包对象作为回调,这里也支持函数名称字符串、对象方法的调用方式回调函数返回了一个字符串,在 test_callback 函数中会得到一个 str 类型返回值可参考下方的 Python tkinter 例子。实际案例基于 tkinter 实现 GUI 的例子<?php$tkinter = PyCore::import('tkinter');$root = $tkinter->Tk();$root->title('我的窗口');$root->geometry("500x500");$root->resizable(False, False);$button = $tkinter->Button($root, text: "Click Me!!", command: PyCore::fn(function () { var_dump(func_get_args()); echo 'click me!!' . PHP_EOL;}));$button->pack();$tkinter->mainloop();一个基于 transformers 的情感分析模型推理实现<?php$transformers = PyCore::import('transformers');$os = PyCore::import('os');$os->environ->__setitem__('https_proxy', getenv('https_proxy'));$distilled_student_sentiment_classifier = $transformers->pipeline( model: "lxyuan/distilbert-base-multilingual-cased-sentiments-student", top_k: null,);$rs = $distilled_student_sentiment_classifier ("I love this movie and i would watch it again and again!");var_dump(PyCore::scalar($rs));
2023年12月18日
12 阅读
0 评论
0 点赞
1
2
3
...
20