本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
Connect 连接到微软 SQL Server 数据源
使用微软 SQL Server (MSSQL) 数据源查询和可视化来自任何微软 SQL Server 2005 或更高版本的数据,包括微软 Azure SQL 数据库。
重要
Grafana 版本 8.0 更改了微软 SQL Server、Postgres 和 MySQL 数据帧的基础数据结构。因此,将以宽格式返回时间序列查询结果。有关更多信息,请参阅 Grafana 数据帧文档中的宽格式
要让你的可视化效果像以前一样工作,你可能需要进行一些手动迁移。Github 上记录了一个解决方案,网址为 Postgres/mySQL/msSQL:v8.0 中与时间序列查询和数据列顺序相关的重大变化
添加数据源
-
选择顶部标题中的 Grafana 图标,打开侧面菜单。
-
在 “配置” 链接下方的侧面菜单中,您应该找到一个 “数据源” 链接。
-
选择顶部标题中的 “+ 添加数据源” 按钮。
-
从 “类型” 下拉列表中选择 “微软 SQL Server”。
数据源选项
名称 | 描述 |
---|---|
Name
|
数据源名称。这就是您在面板和查询中查看数据源的方式。 |
Default
|
默认数据源意味着将为新面板预先选择该数据源。 |
Host
|
您的 MSSQL 实例的 IP 地址/主机名和可选端口。如果省略端口,则将使用默认的 1433。 |
Database
|
您的 MSSQL 数据库的名称。 |
User
|
数据库用户的登录名/用户名。 |
Password
|
数据库用户的密码。 |
Encrypt
|
此选项决定是否或在多大程度上与服务器协商安全 SSL TCP/IP 连接,默认(false Grafana v5.4+)。 |
Max open
|
数据库的最大打开连接数,默认unlimited (Grafana v5.4+)。 |
Max idle
|
空闲连接池中的最大连接数,默认2 (Grafana v5.4+)。 |
Max lifetime
|
可以重复使用连接的最大时间(以秒为单位),默认为 14400 /4 小时。 |
最小时间间隔
$_interval
$_interval_ms
变量的下限。建议设置为写入频率,例如,1m
如果您的数据每分钟写入一次。也可以在仪表板面板的数据源选项下覆盖/配置此选项。此值必须格式化为一个数字,后跟一个有效的时间标识符;例如,1m
(1 分钟)或30s
(30 秒)。支持以下时间标识符。
标识符 | 描述 |
---|---|
y
|
年 |
M
|
月 |
w
|
周 |
d
|
天 |
h
|
小时 |
m
|
分钟 |
s
|
秒 |
ms
|
毫秒 |
数据库用户权限
重要
在添加数据源时指定的数据库用户只能被授予对要查询的指定数据库和表的 SELECT 权限。Grafana 不会验证查询是否安全。该查询可以包括任何 SQL 语句。例如,DROP TABLE user;
将运行DELETE FROM user;
和之类的语句。为了防范这种情况,我们强烈建议您创建具有受限权限的特定 MSSQL 用户。
以下示例代码显示如何创建具有受限权限的特定 MSSQL 用户。
CREATE USER grafanareader WITH PASSWORD 'password' GRANT SELECT ON dbo.YourTable3 TO grafanareader
确保用户没有从公共角色那里获得任何不需要的权限。
已知问题
如果你使用的是较旧版本的微软 SQL Server,例如 2008 和 2008R2,则可能需要禁用加密才能进行连接。如果可能,我们建议您使用最新的 Service Pack 以获得最佳兼容性。
查询编辑器
你可以在图表的 “指标” 选项卡、Singlestat 或表格面板的编辑模式中找到 MSSQL 查询编辑器。要进入编辑模式,请选择面板标题,然后选择 “编辑”。编辑器允许您定义 SQL 查询以选择要可视化的数据。
-
选择 “格式化为”
Time series
(用于图表或 Singlestat 面板等)或Table
(用于表格面板等)。 -
这是你编写 SQL 查询的实际编辑器。
-
在查询编辑器下方显示 MSSQL 的帮助部分。
-
显示已运行的 SQL 查询。将在成功运行查询后首先可用。
-
添加一个额外的查询,其中将显示一个额外的查询编辑器。
宏
为了简化语法并允许使用动态部分,例如日期范围筛选器,查询可以包含宏。
宏观示例 | 描述 |
---|---|
$__time(dateColumn)
|
将替换为表达式,将该列重命名为 t im e。例如,日期列作为时间。 |
$__timeEpoch(dateColumn)
|
将替换为表达式,将 DATETIME 列类型转换为 Unix 时间戳并将其重命名为时间。例如,DATEDIFF(第二,“1970-01-01”,dateColumn)作为时间。 |
$__timeFilter(dateColumn)
|
将替换为使用指定列名的时间范围筛选器。例如,介于 “2017-04-21T 05:01:17 Z” 和 “2017-04-21T 05:06:17 Z” 之间的 Date Column。 |
$__timeFrom()
|
将替换为当前活动时间选择的开头。例如,“2017-04-21T 05:0 1:17 Z”。 |
$__timeTo()
|
将被当前活动时间选择的结尾所取代。例如,“2017-04-21T 05:06: 17 Z”。 |
$__timeGroup(dateColumn,'5m'[, fillvalue])
|
将替换为 GROUP BY 子句中可用的表达式。提供 FillV alue 为 NULL 或浮动值将自动用该值填充时间范围内的空序列。例如,CAST(ROUND(DATEDIFF(第二,“1970-01-01”,time_column)/300.0,0)为 bigint)* 300。 |
$__timeGroup(dateColumn,'5m', 0)
|
与前面相同,但带有填充参数,因此该系列中的缺失点将由 grafana 添加,0 将用作值。 |
$__timeGroup(dateColumn,'5m', NULL)
|
与上面相同,但将使用 NULL 作为缺失点的值。 |
$__timeGroup(dateColumn,'5m', previous)
|
与上面相同,但如果尚未看到任何值,则将使用该系列中的先前值作为填充值(仅在 Grafana 5.3+ 中可用)。 |
查询编辑器有一个 “生成的 SQL” 链接,在面板编辑模式下,该链接会在查询运行后显示。选择它,它将展开并显示已运行的原始插值 SQL 字符串。
表格查询
如果将查询选项设置为 “格式化为表格”,则基本上可以执行任何类型的 SQL 查询。表格面板将自动显示您的查询返回的任何列和行的结果。
以下示例代码显示了一个数据库表。
CREATE TABLE [event] ( time_sec bigint, description nvarchar(100), tags nvarchar(100), )
CREATE TABLE [mssql_types] ( c_bit bit, c_tinyint tinyint, c_smallint smallint, c_int int, c_bigint bigint, c_money money, c_smallmoney smallmoney, c_numeric numeric(10,5), c_real real, c_decimal decimal(10,2), c_float float, c_char char(10), c_varchar varchar(10), c_text text, c_nchar nchar(12), c_nvarchar nvarchar(12), c_ntext ntext, c_datetime datetime, c_datetime2 datetime2, c_smalldatetime smalldatetime, c_date date, c_time time, c_datetimeoffset datetimeoffset ) INSERT INTO [mssql_types] SELECT 1, 5, 20020, 980300, 1420070400, '$20000.15', '£2.15', 12345.12, 1.11, 2.22, 3.33, 'char10', 'varchar10', 'text', N'☺nchar12☺', N'☺nvarchar12☺', N'☺text☺', GETDATE(), CAST(GETDATE() AS DATETIME2), CAST(GETDATE() AS SMALLDATETIME), CAST(GETDATE() AS DATE), CAST(GETDATE() AS TIME), SWITCHOFFSET(CAST(GETDATE() AS DATETIMEOFFSET), '-07:00')
以下示例代码显示了一个查询。
SELECT * FROM [mssql_types]
您可以使用常规 AS
SQL 列选择语法来控制 “表” 面板列的名称,如以下示例代码所示。
SELECT c_bit as [column1], c_tinyint as [column2] FROM [mssql_types]
生成的表格面板:
时间序列查询
例如,如果您将 “格式设置为时间序列”,以便在 “图形” 面板中使用,则查询必须有一个名time
为的列,该列可以返回 SQL 日期时间或任何以秒为单位表示 Unix 纪元的数字数据类型。您可以返回一个名为的列metric
,该列用作值列的指标名称。除time
和之外的任何列metric
都被视为值列。如果省略该metric
列,则值列的名称将是指标名称。您可以选择多个值列,每个值列都将以其名称作为指标。如果您返回多个值列和一个名为的列,metric
则此列将用作系列名称的前缀。
时间序列查询的结果集必须按时间排序。
以下示例代码显示了一个数据库表。
CREATE TABLE [event] ( time_sec bigint, description nvarchar(100), tags nvarchar(100), )
CREATE TABLE metric_values ( time datetime, measurement nvarchar(100), valueOne int, valueTwo int, ) INSERT metric_values (time, measurement, valueOne, valueTwo) VALUES('2018-03-15 12:30:00', 'Metric A', 62, 6) INSERT metric_values (time, measurement, valueOne, valueTwo) VALUES('2018-03-15 12:30:00', 'Metric B', 49, 11) ... INSERT metric_values (time, measurement, valueOne, valueTwo) VALUES('2018-03-15 13:55:00', 'Metric A', 14, 25) INSERT metric_values (time, measurement, valueOne, valueTwo) VALUES('2018-03-15 13:55:00', 'Metric B', 48, 10)
以下示例代码显示了一列value
和一metric
列。
SELECT time, valueOne, measurement as metric FROM metric_values WHERE $__timeFilter(time) ORDER BY 1
当在图表面板中使用前面的查询时,它将生成两个名为 Metric A
and 的序列,Metric B
其中包含值valueOne
并valueTwo
绘制出来time
。
以下示例代码显示了多value
列。
SELECT time, valueOne, valueTwo FROM metric_values WHERE $__timeFilter(time) ORDER BY 1
当在图表面板中使用前面的查询时,它将生成两个名为 Metric A
and 的序列,Metric B
其中包含值valueOne
并valueTwo
绘制出来time
。
以下示例代码演示了如何使用 $__TimeGroup 宏。
SELECT $__timeGroup(time, '3m') as time, measurement as metric, avg(valueOne) FROM metric_values WHERE $__timeFilter(time) GROUP BY $__timeGroup(time, '3m'), measurement ORDER BY 1
当在图表面板中使用前一个查询时,它将生成两个名为Metric A
和Metric B
的序列,其值valueOne
并valueTwo
绘制出来time
。任何两个系列在三分钟窗口中缺少值,都将在这两行之间画一条线。你会注意到右边的图表永远不会降至零。
以下示例代码演示如何使用 $__TimeGroup 宏并将填充参数设置为零。
SELECT $__timeGroup(time, '3m', 0) as time, measurement as metric, sum(valueTwo) FROM metric_values WHERE $__timeFilter(time) GROUP BY $__timeGroup(time, '3m'), measurement ORDER BY 1
在图表面板中使用此查询时,结果是两个名为的序列,Metric A
Metric B
并valueTwo
绘制了time
总和。任何在 3 分钟窗口内缺少值的系列的值都将为零,您将在右边的图表中看到该值呈现。
模板化
不必在指标查询中对服务器、应用程序和传感器名称等内容进行硬编码,而可以使用变量来代替它们。变量显示为仪表板顶部的下拉选择框。您可以使用这些下拉框来更改控制面板中显示的数据。
有关模板和模板变量的更多信息,请参阅模板和变量。
查询变量
如果添加该类型的模板变量Query
,则可以编写一个 MSSQL 查询,该查询可以返回显示为下拉选择框的测量名称、键名或键值之类的内容。
例如,如果您在模板变量 Query 设置中指定这样的查询,则可以有一个包含表中hostname
列所有值的变量。
SELECT hostname FROM host
一个查询可以返回多列,Grafana 会自动根据这些列创建一个列表。例如,以下查询将返回一个包含hostname
和值的列表hostname2
。
SELECT [host].[hostname], [other_host].[hostname2] FROM host JOIN other_host ON [host].[city] = [other_host].[city]
另一种选择是可以创建键/值变量的查询。该查询应返回名为__text
和的两列__value
。__text
列值应该是唯一的(如果它不是唯一的,则使用第一个值)。下拉列表中的选项将具有文本和值,允许您将友好名称作为文本,将ID作为值。一个以文本和id
值hostname
为值的查询示例:
SELECT hostname __text, id __value FROM host
您也可以创建嵌套变量。例如,如果你有另一个名为的变量region
。然后,你可以让 hosts 变量仅通过这样的查询显示当前选定区域的主机(如果region
是多值变量,则使用IN
比较运算符而不是与多个值=
进行匹配)。
SELECT hostname FROM host WHERE region IN ($region)
在查询中使用变量
注意
仅当模板变量为 a 时,才会引用模板变量值multi-value
。
如果该变量是多值变量,则使用IN
比较运算符,而不是与多个值=
进行匹配。
有两种语法:
$<varname>
使用名为的模板变量的示例hostname
:
SELECT atimestamp time, aint value FROM table WHERE $__timeFilter(atimestamp) and hostname in($hostname) ORDER BY atimestamp
[[varname]]
使用名为的模板变量的示例hostname
:
SELECT atimestamp as time, aint as value FROM table WHERE $__timeFilter(atimestamp) and hostname in([[hostname]]) ORDER BY atimestamp
关闭多值变量的引用
Grafana 会自动为多值变量创建带引号的、以逗号分隔的字符串。例如,如果选择了server01
和server02
,则其格式将为:'server01', 'server02'
。要关闭引用,请对变量使用 csv 格式选项。
${servers:csv}
有关变量格式设置选项的更多信息,请参见模板和变量。
注释
您可以使用注释将丰富的事件信息叠加在图表之上。您可以通过仪表板菜单/注释视图添加注释查询。有关更多信息,请参阅 注释。
列:
名称 | 描述 |
---|---|
time
|
日期/时间字段的名称。可以是具有原生 SQL 日期/时间数据类型或纪元值的列。 |
timeend
|
结束日期/时间字段的可选名称。可以是具有原生 SQL 日期/时间数据类型或纪元值的列。 |
text
|
事件描述字段。 |
tags
|
用于事件标签的可选字段名称,以逗号分隔的字符串。 |
以下示例代码显示了数据库表。
CREATE TABLE [events] ( time_sec bigint, description nvarchar(100), tags nvarchar(100), )
我们还使用中定义的数据库表时间序列查询。
以下示例代码显示了使用带有纪元值的时间列的查询。
SELECT time_sec as time, description as [text], tags FROM [events] WHERE $__unixEpochFilter(time_sec) ORDER BY 1
以下示例代码显示了使用带有纪元值的时间和时间结束列的区域查询。
SELECT time_sec as time, time_end_sec as timeend, description as [text], tags FROM [events] WHERE $__unixEpochFilter(time_sec) ORDER BY 1
以下示例代码显示了使用本地 SQL 日期/时间数据类型的时间列的查询。
SELECT time, measurement as text, convert(varchar, valueOne) + ',' + convert(varchar, valueTwo) as tags FROM metric_values WHERE $__timeFilter(time_column) ORDER BY 1
存储过程支持
存储过程已经过验证,可以正常工作。但是,在某些边缘情况下,它可能无法像你预期的那样起作用。表、时间序列和注释查询中应支持存储过程,前提是您使用与前面相应章节中所述相同的列命名并以相同的格式返回数据。
宏函数在存储过程中不起作用。
示例
在以下示例中,数据库表是在时间序列查询中定义的。假设您想在图表面板中可视化四个系列,例如列的所有组合valueOne
,valueTwo
和measurement
。右边的图表面板可视化了我们想要实现的目标。要解决这个问题,你必须使用两个查询:
以下示例代码显示了第一个查询。
SELECT $__timeGroup(time, '5m') as time, measurement + ' - value one' as metric, avg(valueOne) as valueOne FROM metric_values WHERE $__timeFilter(time) GROUP BY $__timeGroup(time, '5m'), measurement ORDER BY 1
以下示例代码显示了第二个查询。
SELECT $__timeGroup(time, '5m') as time, measurement + ' - value two' as metric, avg(valueTwo) as valueTwo FROM metric_values GROUP BY $__timeGroup(time, '5m'), measurement ORDER BY 1
以 epoch 格式使用时间存储过程
您可以定义一个存储过程,该存储过程将返回在图形面板中呈现四个系列所需的所有数据,如上所述。在这种情况下,存储过程接受两个int
数据类型的参数@to
,@from
和,它们应该是纪元格式的时间范围(从-到),用于筛选要从存储过程返回的数据。
这模仿了选择和分组$__timeGroup(time, '5m')
中的表达式,这就是为什么需要大量冗长的表达式的原因。如果需要,可以将它们提取到 MSSQL 函数中。
CREATE PROCEDURE sp_test_epoch( @from int, @to int ) AS BEGIN SELECT cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int) as time, measurement + ' - value one' as metric, avg(valueOne) as value FROM metric_values WHERE time >= DATEADD(s, @from, '1970-01-01') AND time <= DATEADD(s, @to, '1970-01-01') GROUP BY cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int), measurement UNION ALL SELECT cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int) as time, measurement + ' - value two' as metric, avg(valueTwo) as value FROM metric_values WHERE time >= DATEADD(s, @from, '1970-01-01') AND time <= DATEADD(s, @to, '1970-01-01') GROUP BY cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int), measurement ORDER BY 1 END
然后,您可以对图表面板使用以下查询。
DECLARE @from int = $__unixEpochFrom(), @to int = $__unixEpochTo() EXEC dbo.sp_test_epoch @from, @to
使用日期时间格式的时间存储过程
您可以定义一个存储过程,该存储过程将返回在图形面板中呈现四个系列所需的所有数据,如上所述。在这种情况下,存储过程接受两个datetime
数据类型的参数@from
和@to
,这应该是一个时间范围(from-to),用于筛选要从存储过程返回的数据。
这模仿了选择和分组$__timeGroup(time, '5m')
中的表达式,这就是为什么需要大量冗长的表达式的原因。如果需要,可以将它们提取到 MSSQL 函数中。
CREATE PROCEDURE sp_test_datetime( @from datetime, @to datetime ) AS BEGIN SELECT cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int) as time, measurement + ' - value one' as metric, avg(valueOne) as value FROM metric_values WHERE time >= @from AND time <= @to GROUP BY cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int), measurement UNION ALL SELECT cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int) as time, measurement + ' - value two' as metric, avg(valueTwo) as value FROM metric_values WHERE time >= @from AND time <= @to GROUP BY cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int), measurement ORDER BY 1 END
然后,您可以对图表面板使用以下查询。
DECLARE @from datetime = $__timeFrom(), @to datetime = $__timeTo() EXEC dbo.sp_test_datetime @from, @to
提示
时间序列查询应在警报条件下起作用。警报规则条件尚不支持表格格式的查询。