2018年3月28日水曜日

SQL Server テーブルをViewにしたけど一部の項目を更新したいという要望に答えるサンプル

drop table if exists sdemp
create table sdemp (empid int, name nvarchar(200));
drop table if exists emppoint
create table emppoint (empid int, point int);
drop view if exists emp
create view emp as
select se.empid empid, se.[name] [name], isnull(ep.point,0) point
from sdemp se left outer join emppoint ep on ep.empid = se.empid
go
create trigger triggerupdeteemp on emp
instead of update as begin
set nocount on
merge into emppoint using inserted on emppoint.empid = inserted.empid
when matched then update set point = inserted.point
when not matched then insert values(inserted.empid, inserted.point);
end
--sdのテーブル
insert sdemp values(1,'abe')
insert sdemp values(2,'kiyo')
select * from emp
/*
empid name point
1 abe 0
2 kiyo 0
*/
begin tran
update  emp set point = point + 10 where empid = 1
update  emp set point = point + 10 where empid = 1
select * from emp
/*
empid name point
1 abe 10
2 kiyo 0
*/
rollback tran

2018年3月20日火曜日

Enumの名称で使用できない文字がある場合にCustomAttributeを作成して名前付けしてあげてそれを汎用的に取得する拡張メソッドを作るサンプルです。

Enumの名称で使用できない文字がある場合にCustomAttributeを作成して名前付けしてあげてそれを汎用的に取得する拡張メソッドを作るサンプルです。

------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EnumReflectionConsoleApp
{
class Program
{
static void Main(string[] args)
{
foreach (var e in Enum.GetValues(typeof(HogeEnum)) as IEnumerable<HogeEnum>)
{
Console.Out.WriteLine(e.EnumName());
}
Console.In.ReadLine();
}
}

[EnumName("ほげ")]
enum HogeEnum
{
[EnumName("HogeHoge")]
A = 1,
B = 2
}

static class EnumExrentions
{
public static string EnumName(this System.Enum value)
{
var fieldInfo = value.GetType().GetField(value.ToString());
var descriptionAttributes = fieldInfo.GetCustomAttributes(
typeof(EnumNameAttribute), false) as EnumNameAttribute[];
if (descriptionAttributes != null && descriptionAttributes.Length > 0)
return descriptionAttributes[0].Name;
else
return value.ToString();
}

}

[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field)]
public class EnumNameAttribute : Attribute
{
public EnumNameAttribute(string name)
{
this.Name = name;
}

public string Name { get; }
}
}

---取得処理を汎化させてさせてみました。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EnumReflectionConsoleApp
{
class Program
{
static void Main(string[] args)
{
ShowEnumName<HogeEnum>().All(s => { Console.Out.WriteLine(s); return true; });
//HogeHoge
//B
//が出力される
Console.In.ReadLine();
}

static IEnumerable<string> ShowEnumName<T>() where T : struct {
foreach (var e in Enum.GetValues(typeof(T)) as IEnumerable<T>)
{
yield return (e as System.Enum).EnumName();
}
}

}

[EnumName("ほげ")]
enum HogeEnum
{
[EnumName("HogeHoge")]
A = 1,
B = 2
}

static class EnumExrentions
{
public static string EnumName(this System.Enum value)
{
var fieldInfo = value.GetType().GetField(value.ToString());
var descriptionAttributes = fieldInfo.GetCustomAttributes(
typeof(EnumNameAttribute), false) as EnumNameAttribute[];
if (descriptionAttributes != null && descriptionAttributes.Length > 0)
return descriptionAttributes[0].Name;
else
return value.ToString();
}

}

[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field)]
public class EnumNameAttribute : Attribute
{
public EnumNameAttribute(string name)
{
this.Name = name;
}

public string Name { get; }
}
}


2018年3月17日土曜日

Azure:VPN Gatewayで設定できるIPアドレスが動的なIPアドレス(Dynamic IP)だけの問題は、実は問題じゃなかった。ただし、、、

Azure VPNのゲートウェイのPublic IPアドレスですが、ドキュメントの通り「動的なIP」のみが指定可能で、静的なIPアドレスは指定できません。


出展
https://docs.microsoft.com/ja-jp/azure/vpn-gateway/vpn-gateway-vpn-faq


とある要件で、vpn関連の再構築をすることとなり、パブリックIPを消さずに下記の内容を実施した所、、、、IPアドレスが変わってしまうという事象に出くわし、焦りました。
よく見ると「ゲートウェイが削除され、再作成された時のみ」との記載があるので、注意が必要です。

・・・静的なIPが割り当てられれば気軽にVPN Gatewayを再作成することが出来るんですけどね。。。

Azure VPNゲートウェイ(VPN Gateway)を作る際の注意事項。SKUの選択について選択の種類の成約(vpn用に作ったゲートウェイのSKUが途中からBasicに変更できない問題について)

vpn用に作ったゲートウェイのSKUが途中からBasicに変更できない問題について

これは、成約になります。

1)SKUが、Basic, Standard, High Performanceである場合は、Basic, Standard, High Performanceのいずれかにしか変更できません。
2)SKUが、VpnGw1, VpnGw2, VpnGw3である場合は、VpnGw1, VpnGw2, VpnGw3のいずれかにしか変更できません。

ということです。
証拠は↓です。

なので、↓の通り、VPNゲートウェイを作る際に考慮が必要となります。

#■6.VPNゲートウェイを作成する

$gwName = "XXX-vpn-gateway"
#SkuをVpnGw1をやめた
#New-AzureRmVirtualNetworkGateway -Name $gwName -ResourceGroupName $rgName `
#-Location 'Japan West' -IpConfigurations $gwipconfig -GatewayType Vpn `
#-VpnType RouteBased -GatewaySku VpnGw1

#SkuをBasicとする
New-AzureRmVirtualNetworkGateway -Name $gwName -ResourceGroupName $rgName `
-Location 'Japan West' -IpConfigurations $gwipconfig -GatewayType Vpn `
-VpnType RouteBased -GatewaySku Basic

Azure VPN Gatewayの料金
https://azure.microsoft.com/ja-jp/pricing/details/vpn-gateway/

には、ハイブリッドで混ぜてSKUが載っているので、安易に作ってしまうと、作り直しとなってGateway Public IPがリセットされますので、注意が必要です。

私はPublic IPが変わったことでルータの設定がし直しになって手間をこうむりました。

SQL Server:チューニング>複数行を取得する際のユーザ定義関数の使用方法について(処理が遅い場合の対策)

複数行を取得する際に使用するユーザ定義関数のチューニングについて

下記のユーザ定義関数があったとします。
create function fn_GetProductName(@ProductID int)
returns nvarchar(50)
as
begin
  declare @ProductName as nvarchar(50)
  set @productName = (select [name] from Product where ProductID = @ProductID)
  return @productName
end

↓のクエリで10万行を返すような処理をすると処理時間がとても掛かってしまいます。
select fn_GetProductName(ProductID), InStock, ReorderLevel from Inventory

原因は行単位に関数が実行されるているためです。

↓この対策は、ユーザ定義関数を使わずに
1)サブクエリを使用する
select (select [name] from Product P where P.ProductID = I.ProductID), InStock, ReorderLevel from Inventory I

2)inner joinを使用する(関係性によっては、left outer joinとisnullを使ってね。)
select P.[name], InStock, ReorderLevel from Product P
inner join Inventory I on P.ProductID = I.ProductID

などがあります。
良いハード設計に組み込まれたSQL Serverは正しく使えばそれなりに早いです。

SQL Serverでインデックスを上手く使ってくれない場合について(データのバラツキが少ないキー項目に対する処理について)


Customerテーブル(とても大量のデータ)には、clusterd indexがCustomerID、nonclustered indexがStatusがあります。

その場合に、

select CustomerName, Address, City from Customers where Status = @Status

のクエリが非常に異常に遅くなります。実行プランを見てみるとフルスキャン(全走査)が走っています。

原因は、Status列のindexについて統計情報のバラツキ(標準偏差)が小さいのでオプティマイザが平均してフルスキャンしたほうが早いと判断しているのだと考えられます。

この対策については、案が2つあって

1)対象データ量がある程度多い場合は、nonclustered indexにCustomerName, Address, Cityを追加して上げるといい。(バラツキをもたせると同時に、データノードへのアクセスを抑制する)
2)抽出するデータ量が少ない場合は、nonclustered indexをヒント指定が良い。(データノードへの索引が許容できるという判断の場合の選択)

という選択肢があります。

選択における数式的な分岐点は、