转到正文

存档

分类: 程序

SQL Server Business Intelligence Development Studio 中的 Analysis Services 开发工具提供了一个自动生成日期维度的功能,能够很方便的生成带有层次结构的日期维度。但是若想扩展已有日期维度中的时间范围则无法通过开发工具完成。以下提供一个存储过程用于生成日期维度数据。

说明:由于语言环境以及所生成的日期维度结构可存在较大差异,因此本脚本仅供思路参考。在实际应用时应根据具体情况进行改动。

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:  onelittlefox
-- Create date: 2011-01-06
-- Description: Fill date dim for SSAS
-- =============================================
ALTER PROCEDURE [dbo].[FillDateDim]
 -- Add the parameters for the stored procedure here
 @startDate datetime,
 @endDate datetime,
 @operation int = 0
AS
BEGIN
 -- SET NOCOUNT ON added to prevent extra result sets from
 -- interfering with SELECT statements.
 SET NOCOUNT ON;

 -- Insert statements for procedure here
 DECLARE @CurrentDate Datetime;
 SET @CurrentDate = @startDate;
 SET LANGUAGE english;

 IF @operation = 1
 BEGIN
  WHILE @CurrentDate < @endDate
  BEGIN
   INSERT INTO dbo.Dim_Date
   (
    [PK_日期],
    [日期_名称],
    [年],
    [年_名称],
    [季度],
    [季度_名称],
    [月份],
    [月份_名称],
    [每年的某一日],
    [每年的某一日_名称],
    [每个季度的某一日],
    [每个季度的某一日_名称],
    [每月的某一日],
    [每月的某一日_名称],
    [每年的某一月],
    [每年的某一月_名称],
    [每个季度的某一月],
    [每个季度的某一月_名称],
    [每年的某一季度],
    [每年的某一季度_名称]
   )
   VALUES
   (
    @CurrentDate,
    DATENAME(DW, @CurrentDate)+ ', ' + DATENAME(MM, @CurrentDate) + ' '
      + right('00' + CONVERT(char(2), DATEPART(D, @CurrentDate)), 2) + ' ' + CONVERT(char(4), DATEPART(YYYY, @CurrentDate)),
    DATEADD(YYYY, DATEDIFF(YYYY, 0, @CurrentDate), 0),
    'Calendar ' + CONVERT(char(4), DATEPART(YYYY, @CurrentDate)),
    DATEADD(QQ, DATEDIFF(QQ, 0, @CurrentDate), 0),
    'Quarter ' + CONVERT(char(1), DATEPART(QQ, @CurrentDate)) + ', ' + CONVERT(char(4), DATEPART(YYYY, @CurrentDate)),
    DATEADD(MM, DATEDIFF(MM, 0, @CurrentDate), 0),
    DATENAME(MM, @CurrentDate) + ' ' + CONVERT(char(4), DATEPART(YYYY, @CurrentDate)),
    DATEPART(DY, @CurrentDate),
    RTRIM('Day ' + CONVERT(char(3), DATEPART(DY, @CurrentDate))),
    DATEDIFF(D, DATEADD(QQ, DATEDIFF(QQ, 0, @CurrentDate), 0), @CurrentDate) + 1,
    RTRIM('Day ' + CONVERT(char(3),DATEDIFF(D, DATEADD(QQ, DATEDIFF(QQ, 0, @CurrentDate), 0), @CurrentDate) + 1)),
    DATEDIFF(D, DATEADD(MM, DATEDIFF(MM, 0, @CurrentDate), 0), @CurrentDate) + 1,
    RTRIM('Day ' + CONVERT(char(2),DATEDIFF(D, DATEADD(MM, DATEDIFF(MM, 0, @CurrentDate), 0), @CurrentDate) + 1)),
    DATEPART(MM, @CurrentDate),
    RTRIM('Month ' + CONVERT(char(2),DATEPART(MM, @CurrentDate))),
    DATEDIFF(MM, DATEADD(QQ, DATEDIFF(QQ, 0, @CurrentDate), 0), @CurrentDate) + 1,
    RTRIM('Month ' + CONVERT(char(2), DATEDIFF(MM, DATEADD(QQ, DATEDIFF(QQ, 0, @CurrentDate), 0), @CurrentDate) + 1)),
    DATEPART(QQ, @CurrentDate),
    RTRIM('Quarter ' + CONVERT(char(1), DATEPART(QQ, @CurrentDate)))
   );
   SET @CurrentDate = DATEADD(D, 1, @CurrentDate);
  END
 END
 ELSE
 BEGIN
  CREATE TABLE #tmp(
   [PK_日期] [Datetime] NOT NULL,
   [日期_名称] [nvarchar](50) NULL,
   [年] [Datetime] NULL,
   [年_名称] [nvarchar](50) NULL,
   [季度] [Datetime] NULL,
   [季度_名称] [nvarchar](50) NULL,
   [月份] [Datetime] NULL,
   [月份_名称] [nvarchar](50) NULL,
   [每年的某一日] [int] NULL,
   [每年的某一日_名称] [nvarchar](50) NULL,
   [每个季度的某一日] [int] NULL,
   [每个季度的某一日_名称] [nvarchar](50) NULL,
   [每月的某一日] [int] NULL,
   [每月的某一日_名称] [nvarchar](50) NULL,
   [每年的某一月] [int] NULL,
   [每年的某一月_名称] [nvarchar](50) NULL,
   [每个季度的某一月] [int] NULL,
   [每个季度的某一月_名称] [nvarchar](50) NULL,
   [每年的某一季度] [int] NULL,
   [每年的某一季度_名称] [nvarchar](50) NULL
  );
  WHILE @CurrentDate < @endDate
  BEGIN
   INSERT INTO #tmp
   (
    [PK_日期],
    [日期_名称],
    [年],
    [年_名称],
    [季度],
    [季度_名称],
    [月份],
    [月份_名称],
    [每年的某一日],
    [每年的某一日_名称],
    [每个季度的某一日],
    [每个季度的某一日_名称],
    [每月的某一日],
    [每月的某一日_名称],
    [每年的某一月],
    [每年的某一月_名称],
    [每个季度的某一月],
    [每个季度的某一月_名称],
    [每年的某一季度],
    [每年的某一季度_名称]
   )
   VALUES
   (
    @CurrentDate,
    DATENAME(DW, @CurrentDate)+ ', ' + DATENAME(MM, @CurrentDate) + ' '
      + right('00' + CONVERT(char(2), DATEPART(D, @CurrentDate)), 2) + ' ' + CONVERT(char(4), DATEPART(YYYY, @CurrentDate)),
    DATEADD(YYYY, DATEDIFF(YYYY, 0, @CurrentDate), 0),
    'Calendar ' + CONVERT(char(4), DATEPART(YYYY, @CurrentDate)),
    DATEADD(QQ, DATEDIFF(QQ, 0, @CurrentDate), 0),
    'Quarter ' + CONVERT(char(1), DATEPART(QQ, @CurrentDate)) + ', ' + CONVERT(char(4), DATEPART(YYYY, @CurrentDate)),
    DATEADD(MM, DATEDIFF(MM, 0, @CurrentDate), 0),
    DATENAME(MM, @CurrentDate) + ' ' + CONVERT(char(4), DATEPART(YYYY, @CurrentDate)),
    DATEPART(DY, @CurrentDate),
    RTRIM('Day ' + CONVERT(char(3), DATEPART(DY, @CurrentDate))),
    DATEDIFF(D, DATEADD(QQ, DATEDIFF(QQ, 0, @CurrentDate), 0), @CurrentDate) + 1,
    RTRIM('Day ' + CONVERT(char(3),DATEDIFF(D, DATEADD(QQ, DATEDIFF(QQ, 0, @CurrentDate), 0), @CurrentDate) + 1)),
    DATEDIFF(D, DATEADD(MM, DATEDIFF(MM, 0, @CurrentDate), 0), @CurrentDate) + 1,
    RTRIM('Day ' + CONVERT(char(2),DATEDIFF(D, DATEADD(MM, DATEDIFF(MM, 0, @CurrentDate), 0), @CurrentDate) + 1)),
    DATEPART(MM, @CurrentDate),
    RTRIM('Month ' + CONVERT(char(2),DATEPART(MM, @CurrentDate))),
    DATEDIFF(MM, DATEADD(QQ, DATEDIFF(QQ, 0, @CurrentDate), 0), @CurrentDate) + 1,
    RTRIM('Month ' + CONVERT(char(2), DATEDIFF(MM, DATEADD(QQ, DATEDIFF(QQ, 0, @CurrentDate), 0), @CurrentDate) + 1)),
    DATEPART(QQ, @CurrentDate),
    RTRIM('Quarter ' + CONVERT(char(1), DATEPART(QQ, @CurrentDate)))
   );
   SET @CurrentDate = DATEADD(D, 1, @CurrentDate);
  END
  SELECT * FROM #tmp;
  DROP TABLE #tmp;
 END
END

由于 BBS 的一些业务需求,需要使用 PHP 调用 C# 所编写的 WebService,其中遇到一些文档中未提及的细节问题,在此记录一下。

PHP 使用 SoapClient 进行调用,C#返回如下结构:

public struct QueryResult
{
    public bool Result;
    public string Message;
    public string[] Data1;
    public int[] Data2;
}

PHP 的调用代码如下,此处使用异常捕获的方式处理调用失败的情况,若 PHP 不支持异常,应用 is_soap_fault() 判断返回值。与 ASP.net 有关的注意事项写在注释中:

$client = new SoapClient("http://serveraddress/sample.asmx?wsdl");
if ($client !== false)
{
    // 使用关联数组,键名对应C#方法的参数名
    $param = array("Param1" => 1, "Param2" => 2);
    // 可以使用 $client->__soapCall() 或 $client->WebService方法名() 两种方式调用
    // 使用 $client->__soapCall() 调用时应将 $param 再包裹一层
    $result = $client->__soapCall("Method", array("parameters" => $param));
    // 使用 $client->WebService方法名() 调用时无需另行包裹 $param
    $result = $client->Method($param);
    // C# 返回结构体时,访问返回值采用 $result->结构体名称
    $resultdata = $result->Result;
    // bool 变量判断
    if ($resultdata->Result == "True")
    {
        // 访问返回的数组变量时应根据数组长度做不同的处理
        // 对于长度为1的数组,表现为普通变量,不能用下标访问
        if (count($resultdata->Data1) == 1)
        {
            // 用 $resultdata->Data1->string 访问数据
            echo $resultdata->Data1->string;
        }
        else
        {
            // 用 $resultdata->Data1->数据类型[] 访问数据
            echo $resultdata->Data1->string[0];
        }
    }
    catch (Exception $ex)
    {
        echo $ex->getMessage();
    }
}

今天发现某台机器上的一个网站目录下所有的html文件都被在文件末尾加上了一个恶意网站的iframe。机器为Windows系统,没有安装PowerShell等工具,于是写了个bat文件处理这个事情。

被篡改的html文件特征为:

</html><malicious iframe1>
<malicious iframe2>

其中红色的两个iframe为加入的恶意链接。第一个iframe紧接在原有的</html>标记之后,第二个iframe在之后的新行上。为了恢复文件原本内容,需要将这两个iframe移去,并添加上原有的</html>标记。

写了以下的批处理文件完成该目录下所有html和htm文件的修改(一些注意事项以注释的形式写出):

@echo off
rem 将当前路径 %~dp0 保存到环境变量 CurrentBatPath
set CurrentBatPath=%~dp0
rem 从当前目录开始用 for /R 遍历目录

for /R %%j in (.) do (
    cd %%j
    rem 检查目录下所有的htm和html文件(当扩展名为三字母时匹配前三个字母相同的所有扩展名)

    for %%i in (*.htm) do (
        findstr “<malicious iframe1>$^<malicious iframe2>” %%i >nul
        rem 当 findstr 匹配成功时 %errorlevel% 为0,不成功时为 -1
        if %errorlevel% == 0 (
            rem 将两个iframe所在行之外的内容转入新文件。若输出至原始文件会将其内容全部清除
            findstr /V “<malicious iframe1>$^<malicious iframe2>” %%i > %%~ni.new”
            rem 添加</html>标记,^为转义符

            echo ^</html^> >> %%~ni.new”
            del %%i
            ren %%~ni.new” %%i
            rem 显示所修改的文件的完全路径

            echo %%~fi
        )
    )
)
cd %CurrentBatPath%

学校图书馆提供了SciFinder Scholar的授权文件,但是在应用于Mac版的SciFinder Scholar时不起作用。查看授权文件的内容,发现其由若干行无意义的字符组成,其中换行符为CR+LF。联想到Mac平台上传统的换行符为CR,而SciFinder Scholar在早期的Mac系统上已出现,因而猜测将换行符修改为CR可能会有作用。实际操作证实了这一猜测。

Matlab的.m文件,寻找使左右两部分面积相等的点,可能需要根据实际数据的范围调整其中的一些参数。

GetBalancePosition.zip

附带一些测试数据: 继续阅读

Macbook上的双系统,Macdrive的驱动文件在大量IO操作之后有可能导致Windows XP系统
蓝屏,于是打算把Mac的系统盘缩小一些,另外划分一个NTFS分区给Windows用。

分区之前的系统软硬件情况如下:
Macbook MB062,内存扩充至2G
分区表为:
disk0s1 EFI 200MB
disk0s2 HFS+ 80GB   (43G可用空间)
disk0s3 NTFS 31.5GB  (7G可用空间)
操作系统为Mac OS X 10.5.6和Windows XP SP3
Macdrive的版本似乎是7.2.1
手头没有Mac OS X和Windows XP的安装盘,Mac OS X上没有安装第三方的分区软件,安装
有iDefrag Lite。

由于要保持Windows XP的系统盘位于MBR分区表的最后一个,所以计划将Mac OS X的系统
盘disk0s2拆分为两个分区。

按照增加分区的常规操作,需要先启动Windows XP,修改启动文件boot.ini。
在命令提示符下执行
attrib -r -h -s c:\boot.ini
然后打开boot.ini,将其中的两处partition(3)改为partition(4)并保存。
之后在命令提示符下执行
attrib +r +h +s c:\boot.ini
此时Windows系统在分区划分成功之前就无法引导了。
完成上面的操作后重启到Mac OS X,在终端中执行
sudo diskutil resizeVolume disk0s2 50G “MS-DOS FAT32″ newdisk 30G
即可完成增加分区。

但是由于Mac的系统盘中的文件分布较为散乱,分区末尾的剩余空间很少,所以在执行
diskutil操作时提示剩余空间不足,无法实现上述分区目标。此时,若有iDefrag或类似
的HFS+分区碎片整理程序,则可通过光盘启动后整理磁盘碎片使分区中的可用空间集中到
分区尾部,也可使用iPartition的启动光盘执行分区的调整操作。

由于手头没有这两个软件,短时间内也没能从网上下载到,于是改用GParted对HFS+分区
进行调整。用GParted(版本1.8.8)的Live CD启动,将disk0s2(GParted中显示为sda2
)的尺寸缩小到50GB。此过程甚为耗时,花了一个小时完成了分区的缩小。
之后启动到Mac OS X,在终端中执行
sudo diskutil resizeVolume disk0s2 50G “MS-DOS FAT32″ newdisk 30G
成功的创建出新的FAT32分区。

此时系统的分区表为:
disk0s1 EFI 200MB
disk0s2 HFS+ 50GB
disk0s3 FAT32 30GB
disk0s4 NTFS 31.5GB
其中最后一个分区为Windows XP的系统分区。
由于使用了Mac OS X的diskutil创建分区,因此GPT分区表和MBR分区表的内容是同步的。

重新启动电脑,启动时按Alt/Option键,发现仅有Mac OS X的磁盘图标,无法启动到
Windows系统。在Mac OS X的系统预置-启动磁盘中可以认出Windows的分区,但是若指定
从Windows分区启动的话则会在启动时黑屏,提示No bootable device。这是因为MBR分区
表中Windows分区未标记为可引导而导致的。

解决此问题的正确方法为:在Mac OS X的终端中执行
sudo fdisk -e /dev/disk0
在fdisk的界面中输入print,查看MBR分区表中的活动分区,若不是Windows系统所在分区
的话输入flag <分区数字编号>来设置/取消活动分区标记,将Windows系统所在分区设为
活动,然后依次输入w和q保存改动,重启之后即可正常引导。

但是当时又用GParted的Live CD引导,在GParted中查看分区信息,并且执行了一个严重
错误的操作:用GParted修改了Windows系统分区disk0s4(GParted中显示为sda4)的
flag。由于GParted存在一个bug,对于GPT分区表中的FAT32和NTFS分区,若使用
GParted设置了分区的flag,在分区flag不是boot的情况下,flag会固定为msftres。在
Mac OS X系统中,flag为msftres和boot的分区均不能自动挂载,因此在Finder中看不到
对应的磁盘。在Mac OS X的磁盘工具中,对于flag为msftres的分区,分区名称显示为灰
色,无法挂载;对于flag为boot的分区,看不到分区名称,分区表中对应位置显示为可用
空间。同时,使用GParted修改GPT分区之后,会导致MBR分区表被修改为EFI Protective
格式,即MBR分区表中仅有一个EFI分区,占据了所有可用空间,从而导致Windows无法引
导。

为了解决Windows分区的引导问题,下载了gptsync,在Live CD的终端中使用。gptsync可
根据GPT分区表的内容生成对应的MBR分区表,其中flag错误的Windows系统分区在MBR分区
表中被设置为EFI分区,需使用fdisk调整分区的id为NTFS,并设置为活动分区。此后在启
动时按Alt/Option键可看到Windows的磁盘图标,Windows可正常引导,但是Mac OS X中
依然无法自动挂载分区。

为了最终解决Windows分区在GPT分区表中的错误flag问题,在Mac OS X上安装rEFIt,并
使用经修改过的diskpart(文件来源地址见后)将Windows分区的flag改回MSDATA。对于
MB062,diskpart需使用32位的版本,按照文件来源页面中的提示,由rEFIt进入EFI
Shell之后,输入diskpart,然后依次输入
select 0
inspect
chtype 3 MSDATA
即可将错误的flag改掉。
由于diskpart会将MBR分区表改为EFI Protective格式,因此需要再次运行gptsync(在
EFI Shell中)和fdisk(在Mac OS X的终端中)设置MBR分区表。

至此,增加分区的操作全部完成。

修改过的diskpart可从以下地址获得:
http://forum.insanelymac.com/index.php?showtopic=31562

自打4月份在某台域控制器上(汗一下…)恢复.chm文件打包服务之后这已经是第三次要用到这个东西了。头一次非常痛苦的找了一晚上然后查到了这个资料,之后就一直觉得这个东西应当已经发到某个版面上备份起来了。然则后两次需要用到的时候却一直查询未果。索性明确备份一次。。。

发信人: onelittlefox (成功搞定xp上用 Hitachi F-4500), 信区: CPlusPlus
标  题: Re: 关于程序运行错误的处理
发信站: 北大未名站 (2008年10月07日22:59:09 星期二), 转信

HKLM\SYSTEM\CurrentControlSet\Control\Windows分支下面的ErrorMode改成2

http://www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/regentry/29991.mspx?mfr=true

vista和server 2008下面还需要把werfault.exe的运行权限给去掉好像

实验室原有的 Hitachi F-4500 是通过一台装有 Windows 98 系统的电脑进行操作的,其中计算机使用一块国家仪器的 PCI-GPIB 卡与荧光仪进行通信。实验室搬家之后将计算机换为一台装有 Windows XP 系统的机器,需要重新安装驱动程序和控制软件。从 NI 的网站上下载到了 2.6 版的 NI-488.2 驱动程序(260兆,大死了),安装之后发现 Hitachi 的 FL 2.0 控制程序无法检测到荧光仪。购买仪器时所带的设置手册是基于 Windows 98 系统编写的,其中的 GPIB 卡设置部分不适用于 XP 系统。经尝试,使用 NI 的 MAX 程序设置了 GPIB 卡的参数,但是控制程序依然无法找到荧光仪。比对设置手册上的步骤和实际操作步骤,并结合 NI Spy 程序的监控结果,认为问题出在设备名称上。MAX 中可以看到 F-4500 这个设备,设备名称为 DEV1,但是 NI Spy 的结果显示 FL 2.0 试图使用 ibfind() 查找名为 FL 的设备。设置手册上也写明要在 device template 中将荧光仪的设备名改为 FL。经过一段时间查找之后使用 GPIBConf.exe 设置了荧光仪的设备名称,并按照设置手册中的描述修改了其它一些参数。于是 FL 2.0 成功地与 F-4500 建立了通信。经测试,暂时未发现问题。

学院自己设计的选课系统,今年初次启用,用于一个年级约150人的同时选课。选课开始之后很快网站便失去响应。重启服务器之后重新开启选课系统,但是又迅速停止服务。于是选课宣布推迟。

第二次选课安排在某日下午。于第二次选课前一天接手站点维护,对站点的结构和程序性能进行分析。该站点由两台服务器分别负责数据库和Web服务。采用10个并发用户模拟选课过程时,210个事务操作需要10分钟左右。期间Web服务器基本没有负载,而数据库服务器CPU满载。站点数据表尺寸在1M的级别,程序代码中仅有一次锁表操作,但是有若干处在循环中查询数据库。因此推测性能问题是由于对数据库访问次数过多而导致的。

开启数据库的日志并访问课程列表页面,发现仅此一个页面就有200余次数据库查询操作。对课程列表页面进行压力测试发现,数据库服务器每秒可处理近800次查询请求。而一次完整的选课过程则会导致900余次数据库查询。这说明程序结构存在着严重的问题,因此对程序进行重构,消除循环中对于数据库的访问。共将三处循环中对于数据库的访问改为存储过程,另外修改了一些查询语句。同时对数据表项目进行了小的调整,添加了几个表项作为缓存,消除了几处多余查询和重复查询。撤销了两个被频繁调用的且结果稳定的函数中对于数据库的调用,将部分结果暂时硬编码至程序中。另有一处被频繁调用的函数因程序结构原因无法进行快速重构,故而放弃对其的修改。经过上述重构,显示课程列表页面所需的访问数据库次数降低至20次左右,同时由于数据库和程序客户端的问题增加了三次额外的数据库连接操作。应当说这个数据库访问次数仍是偏多的,但是与原先的情况相比有了明显的改进,同时由于程序结构的限制,在短时间内无法进行进一步的优化,因此对程序的优化到此为止告一段落。整个重构过程耗时约12小时。在程序重构的同时,根据网站页面的功能对于部分网页暂时采取了转为静态页面和不显示的方法以降低重构的工作量。优化结束后对课程列表页面进行压力测试,10个客户端连续刷新时Web服务器的CPU占用在40%左右,而数据库服务器的CPU占用在30%附近。

程序重构结束之后,对数据库以及两台服务器的操作系统继续进行优化。根据程序中的查询语句为数据库增添了一些索引,从而使得10个客户端连续刷新课程列表页面时数据库服务器的CPU占用降低至10%以下。此时Web服务器的CPU占用相对较高,同时使用压力测试软件进行测试时响应时间有明显的周期性分布。检查Web服务器的网络连接情况,发现Web服务器端访问数据库的网络连接在程序结束之后没有及时关闭,猜测这可能导致网络连接数过多,从而导致响应时间周期性的分布。因此调整Web服务器的部分网络参数以消除此现象。另外为Web服务器安装了程序脚本的预编译模块以避免重复的脚本编译操作。经过这些优化之后,25个客户端连续刷新课程列表页面时Web服务器的CPU占用降低至20%以下,数据库服务器的CPU占用在15%左右。

分析维护前后系统的性能,对于程序的重构使响应速度提高了近10倍;添加新的数据库索引以及Web程序脚本预编译又各自使得Web服务器和数据库服务器的响应速度翻倍。因此总的来看,维护之后站点的性能提高了近20倍。

次日上午对于网站的内容以及程序逻辑进行进一步的检查,更正了几处数据和逻辑错误。下午选课时,网站负载在选课开始3分钟后达到峰值。Web服务器的峰值CPU占用在15%,而数据库服务器的峰值CPU占用在10%。选课开始10分钟后两服务器已没有明显负载。根据数据库内容的监测,此时大部分学生的选课已基本结束。