使用 Elastic Query 進行跨資料庫存取發生問題時,一些個人在排除問題上的紀錄
在之前 Azure SQL Database 推出 Elastic Query 的時候,曾經寫過一篇「透過 Elastic Query 解決 Azure SQL Database 跨資料庫查詢」,來說明如果當需要跨資料庫存取的方式。而在前一陣子,剛好有朋友問到類似的狀況,於是就很順手的把部落格文章給他,想說又是一個簡單的任務。
沒有想到過了一個星期之後,朋友又發訊息來說,按照我的步驟上去設定,都不是很順利,因此協助他處理得過程中,覺得之前有些地方沒有說清楚,容易造成大家的誤會,因此又整理瞭一下幾個地方。
朋友的環境類似以下的配置,因此他希望在連接 DB1 的時候,還有機會去讀取其他 DB2 , DB3 和 DB4 的資料庫。
問題一:為什麼不能在 master 資料庫下建立 MASTER KEY ?這一點是 Azure SQL Database 的特殊限制,一般我們在地端使用 SQL Server 的時候,建立的 Master Key 都是存在 master 資料庫內,但在 Azure SQL Database 中的時候,master key 只能針對單一資料庫來使用,因此你需要道所在的資料庫下,使用 create master key 指令去建立,這點要稍微注意一下。
問題二:如果要跨在那麼多資料庫,那要建立相對數量的 CREDENTIAL 嗎 ?基本上每個 CREDENTIAL 就是一組的帳號和密碼,但如果你希望管理上方面,在其他的 server 上,都建立相同的帳號和密碼,那麼是可以都共用同一個 CREDENTIAL 。以上述的例子中,我們可以在各資料庫( DB2 , DB3 & DB4 )下去建立一個可以給外部存取的帳號,並賦予資料讀取的權限。
-- 建立帳號
CREATE LOGIN RemoteServer
WITH PASSWORD = 'XYZ@abc987'
GO
-- 建立使用者
CREATE USER RemoteServer
FOR LOGIN RemoteServer
WITH DEFAULT_SCHEMA = dbo
GO
-- 指定權限
ALTER ROLE db_datareader ADD MEMEBR RemoteServer
GO
那麼回到 DB1 ,我們可以使用同樣的 CREDENTIAL ,分別建立不同的資料資料來源,來連到這些不同的資料庫上面去了
CREATE DATABASE SCOPED CREDENTIAL ConnectToOtherDB WITH
IDENTITY = 'RemoteServer',
SECRET = 'XYZ@abc987';
GO
CREATE EXTERNAL DATA SOURCE source1_db2
WITH
(
TYPE=RDBMS,
LOCATION='source1.database.windows.net',
DATABASE_NAME='DB2',
CREDENTIAL= ConnectToOtherDB
);
GO
CREATE EXTERNAL DATA SOURCE source2_db3
WITH
(
TYPE=RDBMS,
LOCATION='source2.database.windows.net',
DATABASE_NAME='DB3',
CREDENTIAL= ConnectToOtherDB
);
GO
CREATE EXTERNAL DATA SOURCE source3_db4
WITH
(
TYPE=RDBMS,
LOCATION='source3.database.windows.net',
DATABASE_NAME='DB4',
CREDENTIAL= ConnectToOtherDB
);
GO
問題三:要怎麼來測試建立的外部資料讀取是可以正常的?在此部分是可以先透過一個 Azure SQL Database 所提供的 SP : sp_execute_remote ,可以用這個指令來針對外部資料來源來下 SQL 指令,因此我們就可以用類似以下的語法,來驗證是否是可以正常來連接外部資料來源。
EXEC sp_execute_remote
N'source1_db2',
N'SELECT DB_NAME()'
EXEC sp_execute_remote
N'source2_db3',
N'SELECT DB_NAME()'
EXEC sp_execute_remote
N'source3_db4',
N'SELECT DB_NAME()'
問題四:要怎麼建立的外部資料表的名稱一定要和實際的資料表名稱相同呢?其實基本上是沒有這樣的限制的,只是外部資料表預設的來源端資料表是相同的 SCHEMA 和物件名稱,因此如果你有不同的話,那麼就要另外來做設定。在我們上述的案例中,因為在 DB2,DB3 和 DB4 下都和 DB1 有相同的資料表,因此我們在建立外部資料表的時候,會習慣的使用 SCHEMA 來做分類,但如果我使用以下的指令來建立的時候,那這樣可能連到 DB2 的時候,他會去抓 DB2.customer 的資料表,造成會有錯誤。
CREATE EXTERNAL TABLE [DB2].[customer](
[c_id] [int] NOT NULL,
[c_firstname] [nvarchar](30) NULL,
[c_lastname] [nvarchar](30) NOT NULL,
[street] [nvarchar](256) NOT NULL,
[city] [nvarchar](20) NOT NULL,
[state] [nvarchar](20) NULL,
[country] [nvarchar](50) NOT NULL
) WITH
(
DATA_SOURCE=source1_db2
)
GO
因此為了避免這樣的問題,最好把指令改成以下的用法,完整的指定 SCHEMA 名稱和物件的名稱,這樣就不會有對應上的異常了。
CREATE EXTERNAL TABLE [DB2].[customer](
[c_id] [int] NOT NULL,
[c_firstname] [nvarchar](30) NULL,
[c_lastname] [nvarchar](30) NOT NULL,
[street] [nvarchar](256) NOT NULL,
[city] [nvarchar](20) NOT NULL,
[state] [nvarchar](20) NULL,
[country] [nvarchar](50) NOT NULL
) WITH
(
DATA_SOURCE=source1_db2,
SCHEMA_NAME = N'dbo',
OBJECT_NAME = N'customer'
)
GO
問題四:如果不同的資料庫有不同的定序,那該怎麼處理呢 ? 目前使用外部資料來源的時候,基本上是比較耗用資源的方式,Azure SQL Database 會直接將外部資料表的資料,都先拉回來到你所使用的資料庫,然後再進行處理,因此如果您有兩個資料庫是不同的定序,基本上當這兩個資料褲上有資料表需要相互關聯的時候,他都會將這些資料表的資料都先帶回到你所連線的資料庫上,然後才做處理。因此目前跨資料庫來做關聯的時候,是可以不用在指令上做特別的處理,就可以來進行的。