首页 > 编程技术 > php

mysql让存储结果分页,用于复杂查询

发布时间:2016-11-25 16:43

mysql让存储结果分页,用于复杂查询。

似乎讨论分页的人很少,难道大家都沉迷于limit m,n?
在有索引的情况下,limit m,n速度足够,可是在复杂条件搜索时,
where somthing order by somefield+somefield
mysql会搜遍数据库,找出“所有”符合条件的记录,然后取出m,n条记录。
如果你的数据量有几十万条,用户又搜索一些很通俗的词,
然后要依次读最后几页重温旧梦。。。mysql该很悲壮的不停操作硬盘。

所以,可以试着让mysql也存储分页,当然要程序配合。
(这里只是提出一个设想,欢迎大家一起讨论)

ASP的分页:在ASP系统中有Recordset对象来实现分页,但是大量数据放在内存中,而且不知道什么时候才失效(请ASP高手指点).
SQL数据库分页:用存储过程+游标方式分页,具体实现原理不是很清楚,设想如果用一次查询就得到需要的结果,或者是id集,需要后续页时只要按照结果中的IDs读出相关记录。这样只要很小的空间保留本次查询的所有IDs. (SQL中的查询结果不知道怎样清楚过期垃圾?)

这样,可以让mysql模拟存储分页机制:
1. select id from $table where $condition order by $field limit $max_pages*$count;
     查询符合条件的IDs.
     限定最大符合条件的记录数量,也可以不加。
2. 因为php在执行结束后所有变量都要lost,所以可以考虑:
     方案a. 在mysql建立临时表,查询结果用一个时间或随机数作为唯一标志插入。
      其中建立page1~pagen个字段,每个字段保存该页中需要的ids, 这样一个id对一条记录.
     方案b. 如果打开session,也可以放在session中保存,实际上是放在文件中保存。
         建立一个$IDs数组,$IDs[1]~$IDs[$max_pages]. 考虑到有时候用户会开几个
         窗口同时查询,要为$ids做一个唯一标志,避免查询结果相互覆盖。二维数组
         和$$var都是好办法。
3. 在每页页的请求中,直接找到对应的IDs,中间以","间隔:
      select * from $table where id in ($ids); 速度绝对快
  mysql可通过两种方式通过PHP与web相连,一种通过php的mysql相关函数,另一种通过php的ODBC相关函数
相关函数如下:
MYSQL函数
mysql_affected_rows: 得到 MySQL 最后操作影响的列数目。
 
mysql_close: 关闭 MySQL 伺服器连线。
 
mysql_connect: 开启 MySQL 伺服器连线。
 
mysql_create_db: 建立一个 MySQL 新资料库。
 
mysql_data_seek: 移动内部传回指标。
 
mysql_db_query: 送查询字串 (query) 到 MySQL 资料库。
 
mysql_drop_db: 移除资料库。
 
mysql_errno: 传回错误讯息代码。
 
mysql_error: 传回错误讯息。
 
mysql_fetch_array: 传回阵列资料。
 
mysql_fetch_field: 取得栏位资讯。
 
mysql_fetch_lengths: 传回单列各栏资料最大长度。
 
mysql_fetch_object: 传回物件资料。
 
mysql_fetch_row: 传回单列的各栏位。
 
mysql_field_name: 传回指定栏位的名称。
 
mysql_field_seek: 设定指标到传回值的某栏位。
 
mysql_field_table: 获得目前栏位的资料表 (table) 名称。
 
mysql_field_type: 获得目前栏位的型态。
 
mysql_field_flags: 获得目前栏位的旗标。
 
mysql_field_len: 获得目前栏位的长度。
 
mysql_free_result: 释放传回占用记忆体。
 
mysql_insert_id: 传回最后一次使用 INSERT 指令的 ID。
 
mysql_list_fields: 列出指定资料表的栏位 (field)。
 
mysql_list_dbs: 列出 MySQL 伺服器可用的资料库 (database)。
 
mysql_list_tables: 列出指定资料库的资料表 (table)。
 
mysql_num_fields: 取得传回栏位的数目。
 
mysql_num_rows: 取得传回列的数目。
 
mysql_pconnect: 开启 MySQL 伺服器长期连线。
 
mysql_query: 送出一个 query 字串。
 
mysql_result: 取得查询 (query) 的结果。
 
mysql_select_db: 选择一个资料库。
 
mysql_tablename: 取得资料表名称。
 

ODBC函数
使用ODBC函数需安装MYSQL ODBC
odbc_autocommit: 开关自动更动功能。
目的: 一台Redhat linux 6.2 用为防火墙,专线连结Chinanet,对内连结
    局域网段192.168.11.0/24,需要enable PHP4和Mysql数据库,且局域网
        上有另一台Apache服务器192.168.11.2,需要对外部用户提供服务,利用
        防火墙上编译的Apache反向代理和名字虚拟主机的功能来实现
地址: 防火墙外部地址为a.b.c.210,且别名第二个地址为a.b.c.211,内部网卡
        地址为192.168.11.5,内部LAN上的Apache服务器为192.168.11.2
实现:
1.下载三个源文件到防火墙机器的/tmp下
apache_1.3.12.tar.gz
mysql-3.22.32.tar.gz    
php-4.0.1pl2.tar.gz
2. 在/tmp下分别解开三个文件
# tar xvfz apache*gz
# tar xvfz mysql*gz
# tar xvfz php*gz
3. 进入/tmp/mysql*,编译mysql
#./configure --prefix=/usr/local/mysql
#make
#make install
#scripts/mysql_install_db
#/usr/local/mysql/bin/safe_mysqld &
#/usr/local/mysql/bin/mysqladm -u root password newpassword
4. 进入/tmp/php*,编译PHP4
#./configure --with-mysql --with-apache=../apche_1.3.12
        --enable-track-vars
#make;make install
5. 下载反向代理X-forward-for模块,地址是
http://perl.apache.org/guide/download.html#mod_proxy_add_forward
下载后放该文件mod_proxy_add_forward.c到/tmp/apache_1.3.12/src/modules/
extra/目录下
5.编译Apache,加入PHP4模块 和大多数共享模块库
./configure --prefix=/usr/local/apache
--activate-module=src/modules/php4/libphp4.a
--activate-module=src/modules/extra/mod_proxy_add_forward.c
--enable-module=most --enable-shared=max
6. 拷贝php.ini-dist到其它目录
# cd /tmp/php*
# cp php.ini-dist /usr/local/lib/php.ini
7.编辑/usr/local/apache/conf/httpd.conf中的AddType行
AddType application/x-httpd-php4 .php
8. 编辑/usr/local/apache/conf/httpd.conf中的AddModule行,
Q. How can I restrict access to my SQL Server so that it only allows certain machines to connect?
(v1.0 19.10.1998)
怎样才能限制我的SQL Server只能让指定的机器连接
A. SQL Server has no built-in tools/facilities to do this. It also does not have the facility to run a stored-procedure on connection that could be written/used to do this. Therefore you have the following choices :-
     SQL Server没有这样的功能,也没有提供在连接时执行某一特定过程的功能。这里介绍几种实现的方法
1. Put the SQL Server behind a firewall and use that to restrict access. This is the most secure and functional way to do what you want.
    使用防火墙,它提供了安全和你想用的工具。
2. Write your own ODS Gateway and point the clients at that instead of the SQL Server - the ODS Gateway will then do the checking. However, there is nothing stopping clients figuring out the correct SQL client-config entries to point straight at the SQL Server. There are examples of ODS code in the SQL Programmers Toolkit - available for free download from the MS website.
    写自己的ODS网关代替SQL Server的客户端 - 在ODS网关中检查。不过,这并不能停止正常的客户端连接SQL Server。在SQL Programmers Toolkit中有一个这样的例, 可以从微软站点免费下载。
3. Write a constantly running/scheduled stored-procedure that checks the relevant column in sysprocesses (net_address), and then issues a KILL command for any processes that should not be running. Note that this only works for MAC addresses. This way allows people to connect and possibly make changes before they are spotted and killed.
    写一个存储过程检查sysprocesses中的相应列(net_address)
 

在维护SQL Server数据库的过程中,大家是不是经常会遇到成千上万的类似log20050901 这种日志表,每一个表中数据都不是很多,一个一个打开看非常不方便,或者有时候我们需要把这些表中的资料汇总,一个一个打开操作也是很麻烦。下面就介绍了一种自动化的合并表的方法。
我的思路是创建一个用户存储过程来完成一系列自动化的操作,以下是代码。
--存储过程我命名为BackupData,可以使用自己定义的名称。
--参数1:@TableTarget 生成的目标表的名称
--参数2:@TableStart 合并开始的表名
--参数3:@TableEnd 合并结束的表名
CREATE PROCEDURE BackupData @TableTarget sysname,@TableStart sysname,@TableEnd sysname
AS
DECLARE tnames_cursor CURSOR
FOR
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
OPEN tnames_cursor
DECLARE @TableName sysname
DECLARE @TablePref sysname
DECLARE @IsTargetExist integer
--判断目标表是否存在

SET @IsTargetExist=(SELECT count(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES where table_name = @TableTarget)
--如果目标表不存在则新建表

IF @istargetexist=0
BEGIN
--EXEC中的语句可以用SQL Server编写的表脚本替换。注意在目标表中不能够存在与需合并表中名称一样的“自动编号”类型的字段。

EXEC ('CREATE TABLE [dbo].[' @TableTarget ']
(
[LOG1] [nvarchar] (10) COLLATE Chinese_PRC_CI_AS NULL ,
[LOG2] [nvarchar] (10) COLLATE Chinese_PRC_CI_AS NULL ,
……
)')
END

FETCH NEXT FROM tnames_cursor INTO @TableName
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN
SELECT @TableName = RTRIM(@TableName)
--以下两行根据日志表的名称更改

--取日志表名的前3位作为标识

SELECT @TablePref = LEFT(@TableName,3)
--判断表名是否附合要求

IF (@TablePref='log') and (@TableName>=@TableStart) and (@TableName<=@TableEnd)
--开始导入

标签:[!--infotagslink--]

您可能感兴趣的文章: