`

《Pro Oracle SQL》Chapter 2--2.4 Identical Statements

阅读更多

2.4 Identical Statements  同样的语句   (page56)

    In order for Oracle to determine if a statement has been previously executed, it will check the library
cache for the identical statement.  You can see what statements are currently stored in the library cache
by querying the v$sql view. 
This view lists statistics on the shared SQL area and contains one row for
each child of the original SQL text entered.  Listing 2-1 shows three different executions of a query
against the employees table followed by a query against v$sql showing information about the three
queries that have been stored in the library cache.
    为了让Oracle判断一条语句是否之前执行过,它将检查库缓存中是否有同样的语句。你可以通过查询视图v$sql知道当前在库缓存中存有什么语句。 该视图列出共享SQL区域的统计信息且对于每个原始(输入)的SQL文本各占一行。列表2-1显示同一对employees表的查询的三个不同的执行,接着是对v$sql的查询,信息显示三条查询都被存入了库缓存中。
Listing 2-1. Queries Against Employees and v$sql Contents
SQL> select * from employees where department_id = 60;
 
    EMPLOYEE_ID  FIRST_NAME             LAST_NAME                 EMAIL ...
---------------   -------------------- ------------------------- -----------  ...
            103        Alexander                 Hunold                     AHUNOLD      ...
            104        Bruce                      Ernst                       BERNST       ...
            105        David                      Austin                      DAUSTIN      ...
            106        Valli                        Pataballa                  VPATABAL     ...
            107        Diana                      Lorentz                    DLORENTZ     ...
            
SQL> SELECT * FROM EMPLOYEES WHERE DEPARTMENT_ID = 60;
 
    EMPLOYEE_ID FIRST_NAME           LAST_NAME                 EMAIL        ...
--------------- -------------------- ------------------------- -----------  ...
            103      Alexander                Hunold                     AHUNOLD      ...
            104      Bruce                     Ernst                       BERNST       ...
            105      David                     Austin                      DAUSTIN      ...
            106      Valli                       Pataballa                  VPATABAL     ...
            107      Diana                     Lorentz                    DLORENTZ     ...

SQL> select /* a_comment */ * from employees where department_id = 60;
 
    EMPLOYEE_ID FIRST_NAME           LAST_NAME                 EMAIL        ...
--------------- -------------------- --------------------- -----------  ...
            103        Alexander              Hunold                    AHUNOLD      ...
            104        Bruce                   Ernst                      BERNST       ...
            105        David                   Austin                     DAUSTIN      ...
            106        Valli                     Pataballa                 VPATABAL     ...
            107        Diana                   Lorentz                   DLORENTZ     ...
            
 
SQL> select sql_text, sql_id, child_number, hash_value, address, executions 
 2   from v$sql where upper(sql_text) like '%EMPLOYEES%';

SQL_TEXT                         SQL_ID             CHILD_NUMBER      HASH_VALUE     ADDRESS  EXECUTIONS
---------------------------   -------------   ------------        ----------        --------   ----------
select * from employees        0svc967bxf4yu       0                3621196762          67197BC4          1
 where department_id = 60                              
SELECT * FROM EMPLOYEES     cq7t1xq95bpm8    0                2455098984          671A3034          1
 WHERE DEPARTMENT_ID = 60                              
select /* a_comment */ *      2dkt13j0cyjzq        0                1087326198          671A2E18          1
  from employees  
 where department_id = 60
 
    Although all three statements return the exact same result, Oracle considers them to be different. 
This is because when a statement is executed, Oracle first converts the string to a hash value.  That hash value is used as the key for that statement when it is stored in the library cache.  As other statements are executed, their hash values are compared to the existing hash values to find a match.
     尽管所有的三条语句返回完全一样的结果,Oracle认为他们是不同的。这是因为当一条语句执行时,Oracle首先转换字符串成哈希值。哈希值作为那条存入库缓存语句的键。 当其他语句执行时,他们的哈希值用来比较存在的哈希值,来查找匹配。

    So, why would these three statements produce different hash values, even though they return the
same result?  It’s because the statements are not exactly identical.  Lower case text is different from
upper case text.  Adding a comment into the statement makes it different from the statements that don’t
have a comment.  Any differences will cause a different hash value for the statement and cause Oracle to
hard parse the statement.

    如此,为什么这三条语句产生了不同的哈希值,即使他们返回相同的结果呢?因为这些语句实际上不是完全的相同。小写文本是不同于大写文本的。在语句中加了注释也有别于语句中没有注释的。任何区别都将产生一个不同的语句哈希值且让Oracle去硬解析这条语句。
    This is why using bind variables instead literals in your SQL statements is so important.  When you
use a bind variable, Oracle will be able to share the statement even as you change the values of the bind
variables
, as shown in Listing 2-2.
    这就是为什么在你的SQL语句中使用绑定变量替代文字是如此重要了。当你使用绑定变量,Oracle将能共享语句即使你改变了绑定变量的值 ,如列表2-2所示。
    Listing 2-2. The Effect of Using Bind Variables on Parsing     使用绑定变量在解析上的效果
SQL> variable v_dept number
SQL> exec :v_dept := 10
SQL> select * from employees where department_id = :v_dept;
 
    EMPLOYEE_ID         FIRST_NAME            LAST_NAME                 EMAIL       ...
    ---------------       --------------------    -------------------------      ----------- ...
            200               Jennifer                      Whalen                        JWHALEN     ...
 
1 row selected.
 
SQL> exec :v_dept := 20
 
PL/SQL procedure successfully completed.

SQL> select * from employees where department_id = :v_dept;
 
    EMPLOYEE_ID      FIRST_NAME           LAST_NAME                 EMAIL       ...
 ---------------      --------------------     -------------------------      ----------- ...
            201                 Michael                       Hartstein                     MHARTSTE    ...
            202                 Pat                             Fay                             PFAY        ...
 
2 rows selected.
 
SQL> exec :v_dept := 30
 
PL/SQL procedure successfully completed.
 
SQL> select * from employees where department_id = :v_dept;
    EMPLOYEE_ID        FIRST_NAME           LAST_NAME                 EMAIL       ...
     ---------------             --------------------         -------------------------      ----------- ...
            114                   Den                          Raphaely                      DRAPHEAL    ...
            115                   Alexander                  Khoo                            AKHOO       ...
            116                   Shelli                         Baida                           SBAIDA      ...
            117                   Sigal                         Tobias                          STOBIAS     ...
            118                   Guy                           Himuro                         GHIMURO     ...
            119                   Karen                        Colmenares                  KCOLMENA    ...
 
6 rows selected.
 
SQL> select sql_text, sql_id, child_number, hash_value, address, executions 
 2   from v$sql where sql_text like '%v_dept';
 
SQL_TEXT            SQL_ID       CHILD_NUMBER   HASH_VALUE     ADDRESS     EXECUTIONS
-------------------------------  -------------   ------------   -----------  --------    ----------
select * from employees     72k66s55jqk1j     0     1260079153     6726254C     3
 where department_id = :v_dept 
 
1 row selected.
 
    Notice how there is only one statement stored in the library cache with three executions.  If I had
executed the queries using the literal values (10, 20, 30), there would have been three different
statements.  Always keep this in mind and try to write SQL that takes advantage of bind variables and
uses exactly the same SQL.  The less hard parsing that is required will mean your applications will
perform better and be more scalable.

    注意三次运行如何却只有一条语句存于库缓存中。如果我使用文本值(10,20,30)执行查询,将生成3条不同的语句。牢记写SQL时尽量使用绑定变量且使用完全相同的SQL。所需的硬解析越少将意味着你的应用将性能更好且越可扩展。
    One last mechanism that is important to understand is something called a latch.  A latch is a type of
lock that Oracle must acquire in order to read information stored in the library cache as well as other
memory structures.  Latches protect the library cache from becoming corrupted by concurrent
modifications by two sessions or by one session trying to read information that is being modified by
another one.  Prior to reading any information from the library cache, Oracle will acquire a latch that will
then cause all other sessions to have to wait until that latch is released before they can acquire the latch
and do the work they need to complete.  

    最后还有被称之为“闩”的机制需要重点理解。闩是一种锁,Oracle必须获取它才能读取库缓存以及其他内存结构中的信息。闩防止库缓存被两个进程并发修改占据或者一个进程在修改某信息的时候另一进程试图读取它。在从库缓存中读取任何信息之前,Oracle将获取闩,从而使得其他进程在他们得到闩之前必须等待闩释放,然后完成他们的工作。
    Latches, unlike typical locks, are not queued.  In other words, if Oracle attempts to acquire a latch
on the library cache in order to check to see if the statement you are executing already exists, it will
check to see if the latch is available.  If the latch is available, it will acquire the latch, do the work it needs to, then release the latch.  However, if the latch is already in use, Oracle will do something called
spinning.  Think of spinning like a kid in the backseat of a car that asks “Are we there yet?” over and over
and over.  Oracle will basically iterate in a loop and continue to check to see if the latch is available. 
During this time, Oracle is actively using CPU to do these checks, but your query is actually “on hold”
and not really doing anything until the latch can be acquired.  
    闩,不像典型的锁,是没有队列的。 换句话说,如果Oracle企图获取库缓存中的一个闩,为了检查看是否你所执行的语句是否已经存在,它将先检查闩是否有效。如果闩有效,它将获取闩,做它要做的工作,然后释放它。然而如果闩已经在使用中,Oracle将做被称之为“自旋”的动作。想象自旋就像一个坐在一辆汽车后座上的小孩不停的一遍又一遍的问“我们到了么?”。Oracle根本上就是在一个循环中不断的迭代检查看闩是否有效了。这期间,Oracle积极的使用CPU做这些检查,但是你的查询实际上hold住了(冻结了),真正没有做任何事情,直到闩获取了。
    If the latch is not acquired after spinning for a while (Oracle will spin up to the number of times
indicated by the _spin_count hidden parameter, which is set to 2000 by default), then the request will be
halted temporarily and your session will have to get in line behind other sessions that need to use the
CPU. It must wait its turn to use the CPU again in order to check to see if the latch is available.  This
iterative process will continue until the latch can be acquired.  You don’t just get in line and wait on the
latch to become available, so it’s entirely possible that another session can acquire the latch while your
session is waiting in line to get back on the CPU to check the latch again.  As you can imagine, this could
be quite time-consuming if many sessions all need to acquire the latch concurrently.
     如果闩在自旋一会后还没有获取(Oracle将旋转到一次数上限,由隐式参数_spin_count设定,默认值2000),请求将被临时的挂起且你的进程将被排到其他需要使用CPU的进程的后面。必须等到轮到他再次使用CPU时检查看是否闩是有效的了。这个迭代过程将继续下去直到闩被获取。你并不是仅按次序等待闩变得有效,因为完全有可能其它的进程先获得闩而当你的进程在排队等待重新获得CPU来检查闩(是否有效)时。你可以想象,如果很多进程并发的需要获得闩这将是非常耗时的。
    The main thing to remember is that latches are serialization devices.  The more frequently Oracle
needs to acquire a latch, the more likely it is that contention will occur, and the longer you’ll have to
wait.  The effects on performance and scalability can be dramatic.  So, writing your code in such a way as to require fewer latches (i.e. less hard parsing) is critical.

    需要记住的要点是闩是序列化装置。Oracle越是频繁的获取一个闩,越可能发生竞争,你就将必须等的越久。对性能和扩展性的效果的影响是巨大的。如此以来,你写代码方式须获取较少的闩(例如:较少的硬解析)是至关重要的。

1
0
分享到:
评论

相关推荐

    常见病虫识别样本-数据集

    来自2021年软件杯A4赛道的数据集,同时我们自己在网上搜集到了对应害虫的幼虫形态,总共15种害虫,同时对每一种害虫都做了标注,存放在Annotations文件里面。 注意:数据分为图片和Xml文件,xml文件里面是框框的坐标,数据有点少,大家也可以自行添加一点,有几个XML文件是空的。

    餐馆点餐管理系统-数据库课程设计-MySQL

    《餐馆点餐管理系统——基于Java和MySQL的课程设计解析》 在信息技术日益发达的今天,餐饮行业的数字化管理已经成为一种趋势。本次课程设计的主题是“餐馆点餐管理系统”,它结合了编程语言Java和数据库管理系统MySQL,旨在帮助初学者理解如何构建一个实际的、具有基本功能的餐饮管理软件。下面,我们将深入探讨这个系统的实现细节及其所涉及的关键知识点。 我们要关注的是数据库设计。在“res_db.sql”文件中,我们可以看到数据库的结构,可能包括菜品表、订单表、顾客信息表等。在MySQL中,我们需要创建这些表格并定义相应的字段,如菜品ID、名称、价格、库存等。此外,还要设置主键、外键来保证数据的一致性和完整性。例如,菜品ID作为主键,确保每个菜品的唯一性;订单表中的顾客ID和菜品ID则作为外键,与顾客信息表和菜品表关联,形成数据间的联系。 接下来,我们来看Java部分。在这个系统中,Java主要负责前端界面的展示和后端逻辑的处理。使用Java Swing或JavaFX库可以创建用户友好的图形用户界面(GUI),让顾客能够方便地浏览菜单、下单。同时,Java还负责与MySQL数据库进行交互,通过JDBC(Java Database Connectivity)API实现数据的增删查改操作。在程序中,我们需要编写SQL语句,比如INSERT用于添加新的菜品信息,SELECT用于查询所有菜品,UPDATE用于更新菜品的价格,DELETE用于删除不再提供的菜品。 在系统设计中,我们还需要考虑一些关键功能的实现。例如,“新增菜品和价格”的功能,需要用户输入菜品信息,然后通过Java程序将这些信息存储到数据库中。在显示所有菜品的功能上,程序需要从数据库获取所有菜品数据,然后在界面上动态生成列表或者表格展示。同时,为了提高用户体验,可能还需要实现搜索和排序功能,允许用户根据菜品名称或价格进行筛选。 另外,安全性也是系统设计的重要一环。在连接数据库时,要避免SQL注入攻击,可以通过预编译的PreparedStatement对象来执行SQL命令。对于用户输入的数据,需要进行验证和过滤,防止非法字符和异常值。 这个“餐馆点餐管理系统”项目涵盖了Java编程、数据库设计与管理、用户界面设计等多个方面,是一个很好的学习实践平台。通过这个项目,初学者不仅可以提升编程技能,还能对数据库管理和软件工程有更深入的理解。在实际开发过程中,还会遇到调试、测试、优化等挑战,这些都是成长为专业开发者不可或缺的经验积累

    校园服务平台系统 2025免费毕设附带论文 SpringBoot+Vue.js

    2025免费毕设附带论文 SpringBoot+Vue.js 启动教程: https://www.bilibili.com/video/BV11ktveuE2d/?share_source=copy_web 二开教程:https://www.bilibili.com/video/BV18i421i7Dx/?share_source=copy_web 讲解视频:https://www.bilibili.com/video/BV1Tb421n72S/?share_source=copy_web

    BlueCoreTM3-Flash:蓝牙2.4GHz系统的单芯片射频与基带IC集成电路解决方案 蓝牙技术

    内容概要:本文详细介绍了BlueCoreTM3-Flash,一款专为蓝牙2.4GHz系统设计的单芯片射频和基带IC。文章首先概述了BlueCoreTM3-Flash的基本特性,包括高集成度、高速处理能力和大容量内存。接着深入探讨了其底层驱动程序和固件代码的设计,展示了如何通过寄存器操作、中断处理和数据处理来实现高效的蓝牙通信和数据传输。最后,文章列举了BlueCoreTM3-Flash在智能耳机、智能手表等多种蓝牙设备中的实际应用场景,强调了其在物联网和智能设备领域的广泛应用前景。 适合人群:对蓝牙技术和集成电路感兴趣的电子工程师、硬件开发者和技术爱好者。 使用场景及目标:①了解BlueCoreTM3-Flash的技术特性和优势;②掌握其底层驱动程序和固件代码的工作原理;③探索其在各类蓝牙设备中的具体应用。 其他说明:本文基于CSR公司的官方资料和技术文档,旨在帮助读者全面理解BlueCoreTM3-Flash的功能及其在蓝牙设备中的重要地位。

    基于COMSOL欧拉-欧拉模型的气固流化床仿真技术解析

    内容概要:本文详细介绍了欧拉-欧拉模型在气固流化床仿真中的应用,重点探讨了该模型如何通过COMSOL仿真软件捕捉气固两相流的复杂交互行为。文章解释了欧拉-欧拉模型的基本原理,即把不同相视为连续介质,以便更精确地模拟和分析各相间的交互作用。文中还强调了COMSOL的强大计算能力和丰富的物理模型库,使得复杂多相流问题得以高效解决。此外,文章讨论了该模型在化工生产中的具体应用场景,如作为反应器或催化剂载体的气固流化床的设计和优化。 适合人群:从事化学工程、流体力学及相关领域的研究人员和技术人员。 使用场景及目标:适用于需要深入了解气固流化床内部流动状态和反应过程的研究项目,旨在优化设备设计和提高生产效率。 其他说明:本文不仅提供了理论背景,还涉及实际操作步骤,包括建模、设定边界条件以及仿真计算,有助于读者全面掌握相关技术和方法。

    疫情防控专题网站系统 2025免费毕设附带论文 SpringBoot+Vue.js

    2025免费毕设附带论文 SpringBoot+Vue.js 启动教程: https://www.bilibili.com/video/BV11ktveuE2d/?share_source=copy_web 二开教程:https://www.bilibili.com/video/BV18i421i7Dx/?share_source=copy_web 讲解视频:https://www.bilibili.com/video/BV1Tb421n72S/?share_source=copy_web

    基于BERT、CRF和BiLSTM的知识图谱医生推荐系统的Python代码及文档与数据集

    毕业设计基于BERT+CRF+BiLSTM知识图谱实现的医生推荐系统,提供python源码、文档说明及数据集。本项目适合计算机相关专业的学生用于毕设或项目实战练习,也可作为课程设计或期末大作业使用。项目经过严格调试,确保可以运行。。内容来源于网络分享,如有侵权请联系我删除。

    宠物商城网站 2025免费毕设附带论文 SpringBoot+Vue.js

    2025免费毕设附带论文 SpringBoot+Vue.js 启动教程: https://www.bilibili.com/video/BV11ktveuE2d/?share_source=copy_web 二开教程:https://www.bilibili.com/video/BV18i421i7Dx/?share_source=copy_web 讲解视频:https://www.bilibili.com/video/BV1Tb421n72S/?share_source=copy_web

    bugreport-2025-05-19-222057.zip

    bugreport-2025-05-19-222057.zip

    基于ADRC控制的Matlab Simulink半车主动悬架建模及其与PID控制的性能对比 ADRC控制 基于ADRC控制的Matlab Simulink半车主动悬架建模:效果对比与输出分析

    内容概要:本文详细探讨了基于ADRC(自抗扰控制)的Matlab Simulink半车主动悬架建模方法及其控制效果。文章首先介绍了半车主动悬架模型的重要性,然后深入讲解了ADRC控制的基本原理及其在悬架系统中的应用。ADRC控制通过自我抗扰实现了对系统的精确控制,尤其适用于非线性、时变和不确定的系统。文中还展示了ADRC控制在车身加速度、悬架动挠度和轮胎动变形等方面的优化表现,并将其与传统的PID控制进行对比,结果显示ADRC控制在复杂路况下表现出显著优势。最后,文章提供了具体的Matlab/Simulink建模和仿真实验步骤,验证了ADRC控制的有效性。 适合人群:汽车工程专业学生、从事车辆控制系统研究的研究人员和技术人员。 使用场景及目标:①理解和掌握ADRC控制在半车主动悬架中的应用;②评估ADRC控制相对于传统PID控制的优势;③利用Matlab/Simulink进行悬架系统建模和仿真。 其他说明:本文不仅提供了理论分析,还包括实际的建模和仿真实例,有助于读者全面理解ADRC控制的实际应用。

    《基于安卓平台的单词学习助手应用开发》

    在安卓开发领域,通过 Android Studio 构建实用的“单词本”应用是一个极具代表性的项目。该应用主要面向学生、语言学习者以及其他希望提升词汇量的用户,旨在帮助他们高效学习和记忆英语单词。 安卓移动开发专注于为安卓设备(如智能手机和平板电脑)开发应用程序。Android Studio 作为谷歌官方推荐的集成开发环境(IDE),提供了代码编辑器、调试器、构建系统和模拟器等强大工具,极大地提升了开发效率。 在“单词本”项目中,Android Studio 的直观界面和丰富功能得到了充分体现。开发者可以利用 XML 设计用户界面,同时使用 Java 或 Kotlin 编写业务逻辑,实现如添加、删除、复习单词等功能。 应用的核心功能包括: 数据存储:采用 SQLite 数据库存储单词及其含义。SQLite 是轻量级的数据库管理系统,可直接嵌入应用中,无需服务器支持。 用户界面:通过多个活动(Activity)展示不同功能,例如主界面显示单词列表,详情页展示单词详细信息,复习界面用于测试用户记忆。 UI 设计:使用 XML 布局文件定义控件布局和样式。Android Studio 的布局编辑器还支持可视化设计,方便开发者操作。 事件处理:通过为按钮等控件设置监听器,响应用户操作(如点击事件),实现添加、删除单词等功能。 通知与提醒:利用安卓的通知 API 和 AlarmManager 服务,提醒用户定期复习单词。 测试与调试:借助 Android Studio 的调试工具,开发者可以进行单元测试和集成测试,设置断点、查看变量值、跟踪代码执行流程,从而发现并修复问题。 开发过程中,Android 模拟器可用于测试应用。模拟器能够模拟不同设备型号和操作系统版本,帮助开发者评估应用的兼容性和性能。 此外,“报告.doc”文件通常详细记录了项目的整体情况,包括目标、设计思路、实现过程

    全自动化瓶盖封装机设备及其控制系统——基于西门子1200PLC与TP900触摸屏的应用

    内容概要:本文介绍了全自动化瓶盖封装机设备的构成和技术应用,特别是博图15.1技术、西门子1200PLC和TP900触摸屏程序的作用。设备由机架、驱动系统、夹具、封装头等部分组成,利用传感器和编码器实现精准封装。博图15.1实现了设备的实时监控、故障诊断和自动报警。西门子1200PLC负责精确控制并与其他设备通信,而TP900触摸屏提供了便捷的操作界面。此外,还提供了视频教程、CAD图纸、PDF文档和IO表等辅助材料,帮助用户理解和操作设备。 适合人群:从事工业自动化设备研发、制造、维护的技术人员,尤其是对PLC编程和人机界面感兴趣的工程师。 使用场景及目标:适用于需要详细了解全自动化瓶盖封装机设备的工作原理和技术细节的专业人士,旨在提高设备的运行效率和稳定性,便于操作和维护。 其他说明:文中提供的多种辅助资料有助于深入理解设备的功能和操作方法,对于实际应用有重要指导意义。

    Delphi 12.3控件之Mitov Runtime version 8-0-0-142 source.rar

    Delphi 12.3控件之Mitov Runtime version 8_0_0_142 source.rar

    基于Simulink仿真的FOC电流环PI参数自整定模型:电机控制系统优化与智能化升级 电机控制 FOC电流环PI参数自整定Simulink仿真模型

    内容概要:本文详细介绍了基于Simulink仿真的FOC电流环PI参数自整定模型及其应用。首先阐述了FOC电流环PI参数自整定的基本原理,即通过传感器输出的角度和速度信息,利用PI控制器实现对电流的精确控制,并根据电机实际运行状态自动调整比例系数和积分系数。接着,重点介绍了该模型的特点,如采用有感FOC控制最小系统、支持无传感器控制升级、标幺值系统便于参数调整、离散式步长仿真确保准确性、模块化结构利于二次开发、所有参数随用随改以及电流环PI参数自动整定。最后,讨论了该模型在电机控制策略研究、不同负载特性的测试以及教育领域的应用价值。 适合人群:从事电机控制技术研发的专业人士、高校师生及相关研究人员。 使用场景及目标:①研究和测试各种电机控制策略;②模拟不同负载特性,评估电机性能;③帮助学生理解和掌握电机控制原理及FOC控制技术。 其他说明:文中提及的PI参数自整定原理参考了知乎的相关文章,提供了进一步的学习资源。

    毕业设计-智慧农场小程序 1.8.9-整站商业源码.zip

    毕业设计-智慧农场小程序 1.8.9-整站商业源码.zip

    爱国评论数据生成及可视化

    生成了评论数据集,根据评论绘制了词云图和情感分析柱状图。

    自创mrt搭建图纸,狙击枪,很帅,真的很帅,需要备课

    韩端mrt,机器人搭建图,这个课常规都不好上,所以建议还是及时换教具,狙击枪使用起来会有bug,如果绳子缠着了,自行松一下就行

    用面对对象求圆和长方形的面积周长.zip

    用面对对象求圆和长方形的面积周长.zip

    毕业设计-景区旅游多商户版3.4.4-整站商业源码.zip

    毕业设计-景区旅游多商户版3.4.4-整站商业源码.zip

    基于单片机的交通灯控制系统的设计与实现.zip

    基于单片机的交通灯控制系统的设计与实现.zip

Global site tag (gtag.js) - Google Analytics