سؤال

لماذا العددية الكرام وظائف يبدو أن يسبب استعلامات لتشغيل تراكمي أبطأ وأكثر من مرة في الخلافة التي يتم استخدامها ؟

لدي هذا الجدول الذي تم بناؤه مع البيانات التي تم شراؤها من 3rd الطرف.

لقد قلصت بعض الاشياء لجعل هذا المنصب أقصر...ولكن فقط حتى تحصل على فكرة عن كيف تسير الامور الإعداد.

CREATE TABLE [dbo].[GIS_Location](
        [ID] [int] IDENTITY(1,1) NOT NULL, --PK
        [Lat] [int] NOT NULL,
        [Lon] [int] NOT NULL,
        [Postal_Code] [varchar](7) NOT NULL,
        [State] [char](2) NOT NULL,
        [City] [varchar](30) NOT NULL,
        [Country] [char](3) NOT NULL,

CREATE TABLE [dbo].[Address_Location](
    [ID] [int] IDENTITY(1,1) NOT NULL, --PK
    [Address_Type_ID] [int] NULL,
    [Location] [varchar](100) NOT NULL,
    [State] [char](2) NOT NULL,
    [City] [varchar](30) NOT NULL,
    [Postal_Code] [varchar](10) NOT NULL,
    [Postal_Extension] [varchar](10) NULL,
    [Country_Code] [varchar](10) NULL,

ثم لدي اثنين من الوظائف التي تبحث عن خطوط الطول و العرض.

CREATE FUNCTION [dbo].[usf_GIS_GET_LAT]
(
    @City VARCHAR(30),
    @State CHAR(2)
)
RETURNS INT 
WITH EXECUTE AS CALLER
AS
BEGIN
    DECLARE @LAT INT

    SET @LAT = (SELECT TOP 1 LAT FROM GIS_Location WITH(NOLOCK) WHERE [State] = @State AND [City] = @City)

RETURN @LAT
END


CREATE FUNCTION [dbo].[usf_GIS_GET_LON]
(
    @City VARCHAR(30),
    @State CHAR(2)
)
RETURNS INT 
WITH EXECUTE AS CALLER
AS
BEGIN
    DECLARE @LON INT

    SET @LON = (SELECT TOP 1 LON FROM GIS_Location WITH(NOLOCK) WHERE [State] = @State AND [City] = @City)

RETURN @LON
END

عند تشغيل التالية...

SET STATISTICS TIME ON

SELECT
    dbo.usf_GIS_GET_LAT(City,[State]) AS Lat,
    dbo.usf_GIS_GET_LON(City,[State]) AS Lon
FROM
    Address_Location WITH(NOLOCK)
WHERE
    ID IN (SELECT TOP 100 ID FROM Address_Location WITH(NOLOCK) ORDER BY ID DESC)

SET STATISTICS TIME OFF

100 ~= 8 ms, 200 ~= 32 ms, 400 ~= 876 ms

- تحرير آسف كان يجب أن أكون أكثر وضوحا.أنا لا أبحث عن لحن الاستعلام المذكورة أعلاه.هذا هو مجرد عينة لإظهار وقت التنفيذ الحصول على أبطأ وأكثر يسجل عليه من خلال الجرش.في العالم الحقيقي تطبيق وظائف تستخدم كجزء من حيث شرط لبناء دائرة نصف قطرها حول المدينة لتشمل كافة السجلات في تلك المنطقة.

هل كانت مفيدة؟

المحلول

في معظم الحالات فإنه من الأفضل تجنب العددية الكرام الوظائف التي الجداول المرجعية لأنه (كما قال آخرون) وهم أساسا الصناديق السوداء التي تحتاج إلى أن تكون ركض مرة واحدة لكل صف ، و لا يمكن أن يكون الأمثل من خلال خطة الاستعلام المحرك.وبالتالي فإنها تميل إلى نطاق خطيا حتى لو المرتبطة الجداول والفهارس.

قد ترغب في النظر في استخدام inline-table-دالة قيم ، حيث يتم تقييم مضمنة مع الاستعلام ، و يمكن أن يكون الأمثل.يمكنك الحصول على تغليف تريد ، ولكن أداء لصق عبارات الحق في عبارة select.

كأثر جانبي من كونها المضمنة, أنها لا يمكن أن تحتوي على أي قانون الإجراءات (لا تعلن @متغير ؛ مجموعة @متغير = ..;العودة).ومع ذلك ، فإنها يمكن أن عودة العديد من الصفوف والأعمدة.

هل يمكن إعادة كتابة وظائف شيئا من هذا القبيل:

create function usf_GIS_GET_LAT(
    @City varchar (30),
    @State char (2)
)
returns table
as return (
  select top 1 lat
  from GIS_Location with (nolock) 
  where [State] = @State
    and [City] = @City
);

GO

create function usf_GIS_GET_LON (
    @City varchar (30),
    @State char (2)
)
returns table
as return (
  select top 1 LON
  from GIS_Location with (nolock)
  where [State] = @State
    and [City] = @City
);

جملة استخدامها أيضا مختلفة قليلا:

select
    Lat.Lat,
    Lon.Lon
from
    Address_Location with (nolock)
    cross apply dbo.usf_GIS_GET_LAT(City,[State]) AS Lat
    cross apply dbo.usf_GIS_GET_LON(City,[State]) AS Lon
WHERE
    ID IN (SELECT TOP 100 ID FROM Address_Location WITH(NOLOCK) ORDER BY ID DESC)

نصائح أخرى

فإنها لا.

لا يوجد أي خلل في الدالات العددية التي تسبب أدائها للحط من أضعافا مضاعفة اعتمادا على عدد من الصفوف في العددية يتم تنفيذ الدالة ضد.محاولة الاختبارات الخاصة بك مرة أخرى و ننظر في منشئ ملفات التعريف SQL ، وتبحث في وحدة المعالجة المركزية يقرأ مدة الأعمدة.زيادة اختبار حجم تشمل الاختبارات التي تستغرق وقتا أطول من الثانية ، ثانيتين خمس ثوان.

CREATE FUNCTION dbo.slow
(
    @ignore int
)
RETURNS INT 
AS
BEGIN
    DECLARE @slow INT
    SET @slow = (select count(*) from sysobjects a 
        cross join sysobjects b 
        cross join sysobjects c 
        cross join sysobjects d 
        cross join sysobjects e 
        cross join sysobjects f
    where a.id = @ignore) 

    RETURN @slow
END
go
SET STATISTICS TIME ON

select top 1 dbo.slow(id)
from sysobjects
go
select top 5 dbo.slow(id)
from sysobjects
go
select top 10 dbo.slow(id)
from sysobjects
go
select top 20 dbo.slow(id)
from sysobjects
go
select top 40 dbo.slow(id)
from sysobjects

SET STATISTICS TIME OFF

الإخراج

SQL Server Execution Times:
   CPU time = 203 ms,  elapsed time = 202 ms.


SQL Server Execution Times:
   CPU time = 889 ms,  elapsed time = 939 ms.

SQL Server Execution Times:
   CPU time = 1748 ms,  elapsed time = 1855 ms.

SQL Server Execution Times:
   CPU time = 3541 ms,  elapsed time = 3696 ms.


SQL Server Execution Times:
   CPU time = 7207 ms,  elapsed time = 7392 ms.

نضع في اعتبارنا أنه إذا كنت تقوم بتشغيل وظيفة عددية ضد الصفوف في مجموعة النتائج ، عددي الوظيفة سوف يتم تنفيذها في الصف مع عدم العالمية الأمثل.

يمكنك التفاف على وظائف مضمنة TVF أن يكون أسرع من ذلك بكثير:

http://sqlblog.com/blogs/alexander_kuznetsov/archive/2008/05/23/reuse-your-code-with-cross-apply.aspx

يمكنك استدعاء الدالة مرتين (اثنين حدد يضرب إلى DB) لكل صف في مجموعة النتائج.

لجعل الاستعلام الخاص بك أسرع الانضمام إلى الحق GIS_Location و تخطي المهام:

SELECT
    g.Lat,
    g.Lon
FROM
    Address_Location        l WITH(NOLOCK)
    INNER JOIN GIS_Location g WITH(NOLOCK) WHERE l.State = g.State AND l.City = g.City
WHERE
    ID IN (SELECT TOP 100 ID FROM Address_Location WITH(NOLOCK) ORDER BY ID DESC)

لست متأكدا لماذا NOLOCK أو مجنون حيث شرط, أنا فقط نسخ من السؤال...

ببساطة, لأن عبارات SQL مع معرف المستخدم وظائف أقل كفاءة من عبارات SQL بدونها.تنفيذ المنطق لا يمكن أن يكون الأمثل;وظيفة النفقات العامة (بما في ذلك الدعوة البروتوكولات) يجب أن يكون المتكبدة في كل صف.

KMike نصيحة جيدة.حيث ..في (تحديد شيء) ليس من المرجح أن تكون فعالة نمط ، و في هذه الحالة يمكن استبدالها بسهولة مع الانضمام.

ترى إذا كان هذا يعمل بشكل أفضل...أو ربما متميزة الداخلية الانضمام ؟

select a.*,
(select top 1 g.Lat from GIS_Location g where g.City = a.City and g.State = a.State) as Lat,
(select top 1 g.Lon from GIS_Location g where g.City = a.City and g.State = a.State) as Lon
from Address_Location a
where a.ID in (select top 100 ID from Address_Location order by ID desc)

أما بالنسبة العددية وظيفة الأداء, أنا لست متأكدا.

عادة الدالات العددية هي أبطأ بكثير من مضمنة TVF نظرائهم.لحسن الحظ العديد من السيناريوهات فإنه سيتم تغيير.

SQL Server 2019 سوف أعرض العددية UDF Inlining:

ميزة تحت ذكي معالجة الاستعلام عن مجموعة من الميزات. هذه الميزة يحسن أداء الاستعلامات التي تحتج العددية UDFs في SQL Server (بدءا من SQL Server 2019 المعاينة)

T-SQL العددية الدالات المعرفة من قبل المستخدم

الدالات المعرفة من قبل المستخدم التي يتم تنفيذها في Transact-SQL والعودة واحد قيمة البيانات يشار إلى T-SQL العددية الدالات المعرفة من قبل المستخدم. T-SQL UDFs هي وسيلة أنيقة لتحقيق إعادة استخدام التعليمات البرمجية و نمطية عبر استعلامات SQL.بعض العمليات الحسابية (مثل الأعمال المعقدة القواعد) هي أسهل في التعبير عن حتمية UDF شكل.UDFs تساعد في بناء منطق معقدة دون الحاجة إلى خبرة في كتابة استعلامات SQL معقدة.

UDFs مفردة عادة في نهاية المطاف أداء ضعيفا نظرا للأسباب التالية.

  • تكرارية الاحتجاج
  • وعدم تكلف
  • تفسير التنفيذ
  • المسلسل التنفيذ

التلقائي Inlining من العددية UDFs

الهدف من العددية UDF inlining الميزة لتحسين الأداء من الاستفسارات التي تحتج T-SQL العددية UDFs ، حيث UDF التنفيذ هو عنق الزجاجة الرئيسي.

مع هذه الميزة الجديدة ، UDFs مفردة تحول تلقائيا إلى التعبيرات العددية أو العددية الاستعلامات الفرعية التي يتم استبداله في الدعوة الاستعلام في مكان UDF المشغل.هذه التعبيرات و الاستعلامات الفرعية ثم الأمثل. ونتيجة لذلك ، فإن خطة الاستعلام سوف لم يعد لدينا دالة معرفة من قبل المستخدم المشغل ، ولكن آثارها ستكون لوحظ في الخطة ، مثل آراء أو مضمنة TVFs.


Inlineable العددية UDFs متطلبات

العددية T-SQL UDF يمكن أن تكون مضمنة إذا كافة الشروط التالية صحيحا:

  • UDF هو مكتوب باستخدام التالية بنيات:

    1. تعلن مجموعة:تعريف متغير والواجبات.
    2. حدد:استعلام SQL مع واحد/متعددة المتغير assignments1.
    3. إذا/آخر:المتفرعة مع التعسفي مستويات من التداخل.
    4. العودة:واحدة أو متعددة عودة البيانات.
    5. UDF:متداخلة/وظيفة العودية calls2.
    6. الآخرين:العلائقية العمليات مثل موجودا ، ISNULL.
  • UDF لا يحتج أي الجوهرية وظيفة إما أن تعتمد على الوقت (مثل GETDATE()) أو الجانب effects3 (مثل NEWSEQUENTIALID()).

  • UDF يستخدم تنفيذ المتصل البند (السلوك الافتراضي إذا تم تنفيذ بند لم يتم تحديد).
  • UDF لا مرجع متغيرات الجدول أو الجدول قيم المعلمات.
  • الاستعلام الاحتجاج العددية UDF لا مرجع العددية UDF الاتصال في المجموعة BY.
  • UDF ليست أصلا جمعت (interop معتمد).
  • UDF لا يستخدم في عمود محسوب أو تحقق القيد التعريف.
  • UDF لا مرجع الأنواع المعرفة من قبل المستخدم.
  • لا توجد التوقيعات إضافة إلى UDF.
  • UDF ليست دالة قسم.

فحص إذا كانت وظيفة inlinable:

SELECT OBJECT_NAME([object_id]) AS name, is_inlineable
FROM sys.sql_modules
WHERE [object_id] = OBJECT_ID('schema.function_name')

تمكين/تعطيل ميزة على مستوى قاعدة البيانات:

ALTER DATABASE SCOPED CONFIGURATION SET TSQL_SCALAR_UDF_INLINING = ON/OFF;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top